<?php

/**
 * 订单
 */

namespace app\admin\service;

use app\admin\model\Images;
use app\admin\model\OrderItem;
use app\api\logic\CacheLogic;
use app\common\Common;

use app\common\RedisClient;
use app\common\shopify\FulfillmentService;
use app\common\shopify\OrderService;
use Exception;
use think\facade\Db;
use app\admin\model\Order as OrderModel;
use app\admin\model\Inventory as InventoryModel;
use app\admin\model\Address as AddressModel;
use app\admin\model\OrderItem as OrderItemModel;
use app\admin\model\Warehouse as WarehouseModel;
use app\admin\model\LogisticsCompany as LogisticsCompanyModel;
use app\admin\model\LogisticsOrder as LogisticsOrderModel;
use app\admin\service\LogisticsRules as AdminServiceLogisticsRules;
use app\admin\model\Customer as CustomerModel;
use app\admin\service\ProductInventory as ProductInventoryService;
use app\admin\model\BusinessLog;
use app\admin\model\Filingcabinet;
use app\admin\logic\Order\WholesalAssets;
use app\admin\model\InventoryChangeRecord;
use app\admin\model\PurchaseOrders;
use app\api\model\Inventory;
use app\common\service\Mail;
use think\file\UploadedFile;
use app\common\ExchangeRateHostAPI;
use app\api\service\GoAffPro;
use app\common\service\Inventory as InventoryService;
use app\common\service\CompleteNotificationService;
use think\facade\Log;
use app\admin\model\ProductPrice as PriceModel;
use app\admin\model\SystemConfig as SystemConfigModel;
use app\admin\model\OrderPayment as OrderPaymentModel;
use app\common\service\Inventory as CommonInventoryService;
use app\admin\logic\Order\OrderTransSaveLogic;
use app\admin\logic\Order\Index as OrderLogic;
use app\admin\logic\Order\ImporAndExport as ImporAndExportLogic;

class Order extends BaseService
{
    /**
     * 获取订单列表
     * @param $param
     * @param $page
     * @param $limit
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getList($param = [], $page = 1, $limit = 10)
    {

        $where['o.is_del'] = 0;

        $arrData = ['code' => 0, 'message' => 'success'];
        if ($param['order_category'] != null) {
            if ($param['order_category'] == 'order') {
                $where['o.order_category'] = 'order';
            } else {
                $where['o.order_category'] = 'wholesal';
            }
        }

        if ($param['order_no']) {
            $where[] = ['o.order_no', 'like', '%' . $param['order_no'] . '%'];
        }
        if ($param['order_type']) {
            $where[] = ['order_type', '=', $param['order_type']];
        }
        if ($param['delivery_method'] > -1) {
            $where[] = ['delivery_method', '=', $param['delivery_method']];
        }
        if ($param['order_status']) {
            $where[] = ['o.status', 'in', explode(',', $param['order_status'])];
        }
        if ($param['pay_status']) {
            $where[] = ['pay_status', 'in', explode(',', $param['pay_status'])];
        }
        if ($param['aftersales_status']) {
            $where[] = ['aftersales_status', 'in', explode(',', $param['aftersales_status'])];
        }
        if ($param['exceptionstatus']) {
            // exceptionstatus 模糊匹配：只要包含查询参数中的任意一个状态值即可
            $exceptionStatusArray = explode(',', $param['exceptionstatus']);
            $exceptionStatusArray = array_map('trim', $exceptionStatusArray); // 去除空格
            $exceptionStatusArray = array_unique($exceptionStatusArray); // 去重

            $conditions = [];
            foreach ($exceptionStatusArray as $status) {
                $conditions[] = "exceptionstatus LIKE '%{$status}%'";
            }
            $where[] = ['', 'exp', Db::raw('(' . implode(' OR ', $conditions) . ')')];
        }

        if ($param['owner']) {
            $where[] = ['o.owner', '=', $param['owner']];
        }
        if ($param['partner']) {
            $where[] = ['o.partner', '=', $param['partner']];
        }

        if ($param['start_date']) {
            $where[] = ['o.create_time', '>=', $param['start_date']];
        }
        if ($param['end_date']) {
            $where[] = ['o.create_time', '<=', $param['end_date']];
        }
        if (isset($param['user_id']) && !empty($param['user_id'])) {
            $where[] = ['o.user_id', 'in', $param['user_id']];
        }
        if (isset($param['id']) && !empty($param['id'])) {
            $where[] = ['o.id', '=', $param['id']];
        }
        if (isset($param['username']) && $param['username']) {
            $userIds = Db::name('customer')->where([
                'is_del' => 0,
            ])->whereLike('cusname', '%' . $param['username'] . '%')->field('id')->select()->toArray();
            if (count($userIds)) {
                $where[] = ['o.user_id', 'in', implode(',', array_column($userIds, 'id'))];
            }
        }

        $itemWhere = [];
        if (isset($param['product_id']) && $param['product_id']) {
            $itemWhere[] = ['product_id', 'in', $param['product_id']];
        }

        if (isset($param['source']) && $param['source'] !== null) {
            $where[] = ['o.source', '=', $param['source']];
        }

        if (isset($param['warehouse_id']) && $param['warehouse_id']) {
            $itemWhere[] = ['warehouse_id', 'in', $param['warehouse_id']];
        }

        if (isset($param['is_futures']) && $param['is_futures'] !== null && $param['is_futures'] !== '') {
            $itemWhere[] = ['is_futures', '=', $param['is_futures']];
        }

        $field = [
            'o.id',
            "concat(coalesce(c.cusname,''), if(c.email > '', concat(' (', c.email, ')'), '')) as user",
            'order_no',
            'id_number',
            "concat (ifnull(o.first_name,''),' ',ifnull(o.last_name,'')) consignee",
            'o.user_id',
            'o.phone',
            'o.address',
            'o.country_name',
            'o.signatory',
            'o.signing_date',
            'o.contract_signing_status',
            'o.owner',
            'o.single_order_method',
            'o.partner',
            'o.product_total_original_amount',
            'o.total_amount',
            'o.logistics_fee',
            'o.notes',
            'o.order_remark',
            'o.pay_status',
            'o.pay_terms',
            'o.payment_deadline',
            'o.shipping_start_date',
            'o.shipping_end_date',
            'o.creator',
            'o.create_time',
            'o.updater',
            'o.update_time',
            'o.review_node',
            'o.order_category',
            'o.exceptionstatus',
            'order_type',
            'delivery_method',
            'total_amount',
            'o.status as order_status',
            'pay_status',
            'pay_terms',
            'currency',
            'notes',
            'payment_method as pay_method',
            'pay_amount',
            'o.source',
            'o.aftersales_status'
        ];
        $oOrderModel = OrderModel::table('db_order')
            ->with(['itemList'])
            ->alias('o')
            ->leftJoin('db_customer c', 'o.user_id = c.id')
            ->where($where)
            ->whereIn('o.id', function ($query) use ($itemWhere) {
                $query->name('order_item')
                    ->where('is_del', 0)
                    ->where(function ($query) use ($itemWhere) {
                        if (count($itemWhere) > 0) {
                            $query->where($itemWhere);
                        }
                    })
                    ->field('order_id');
            });
        $total = $oOrderModel->count();
        $result = $oOrderModel->field($field)
            ->page($page, $limit)
            ->order('id desc')
            ->select();
        $order_list = [];
        foreach ($result as $value) {
            $order_list[] = $value['id'];
        }
        $not_now = OrderItemModel::where('order_id', 'in', $order_list)->where('is_del', 0)->where('is_futures', '<>', 0)->where('quantity', '>', 0)->column('order_id');
        $data = $result->toArray();

        foreach ($data as &$item) {
            $item['show_entry'] = (in_array($item['id'], $not_now) && $item['pay_status'] == 3 && $item['review_node'] == 0);
            $item['buy_goods'] = [];
            if ($item['itemList']) {
                foreach ($item['itemList'] as $itemList) {
                    $enum = InventoryModel::getStaticEnum();
                    $is_futures_enum = $enum['is_futures'];
                    $item['buy_goods'][] = [
                        'warehouse_name' => $itemList['warehouse_name'],
                        'is_futures' => $is_futures_enum[$itemList['is_futures']],
                        'code' => $itemList['code'],
                        'quantity' => $itemList['quantity'],
                        'wholesal_id' => $itemList['wholesal_id']
                    ];
                }
            }
            unset($item['itemList']);
        }
        $arrData['data'] = ['list' => $data, 'total' => $total];
        return $arrData;
    }


    /**
     * 删除单条或多条订单数据 此方法没有释放资产，所以暂时废弃
     * @param $param
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function deleteDiscard($param)
    {
        $where = [['is_del', '=', '0'], ['id', 'in', $param['ids']]];
        $oOrderModel = OrderModel::where($where)->find();
        if (!$oOrderModel) {
            return ['code' => 1, 'message' => '获取订单信息失败！'];
        }
        $result = $oOrderModel->update(['is_del' => time()]);
        if ($result) {
            $this->logger->logOperation($param['ids'], 'order', '删除', '删除订单');
            return ['code' => 0, 'message' => '删除订单成功！'];
        } else {
            return ['code' => 1, 'message' => '删除订单失败！'];
        }
    }

    /**
     * 删除单条
     * @param $param
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function del($param)
    {
        $where = [['is_del', '=', '0'], ['id', '=', $param['ids']]];
        $oOrderModel = OrderModel::where($where)->whereRaw('(pay_status = 1 and status = 10) or status = 70')->find();
        if (!$oOrderModel) {
            return ['code' => 1, 'message' => '获取订单信息失败！'];
        }
        Db::startTrans();
        try {
            if ($oOrderModel->order_type == 2 && $oOrderModel->status != 70) { // 经销商发货单 取消的时候已经释放了，避免重复释放资产
                // 如果为经销商发货单 释放经销商资产
                $orderItems = $oOrderModel->items->toArray();
                $wholesalAssets = new WholesalAssets();
                $result = $wholesalAssets->releaseAssets($orderItems);
                if ($result['code'] != 0) {
                    throw new \Exception($result['message']);
                }
            }

            $result = OrderModel::where($where)->whereRaw('(pay_status = 1 and  status = 10) or status = 70')->update(['is_del' => time()]);
            if (!$result) {
                throw new Exception("订单删除失败");
            }

            $oi = OrderItem::where('order_id', $oOrderModel->id)->update(['is_del' => time()]);
            if (!$oi) {
                throw new Exception("订单明细删除失败");
            }

            $this->logger->logOperation($param['ids'], 'order', '订单-删除', '删除订单');
            DB::commit();
        } catch (Exception $e) {
            Db::rollback();
            return ['code' => 1, 'message' => $e->getMessage()];
        }

        return ['code' => 0, 'message' => '删除订单成功'];
    }

    /**
     * 添加修改订单
     * @param $param
     * @return array|void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function save($param)
    {
        Log::info('订单创建参数：' . json_encode($param, JSON_UNESCAPED_UNICODE));
        $productList =  $param['list'];
        $conditions = [];
        foreach ($productList as $key => $item) {
            $conditions[$key]['productid'] = $item['product_id'];
            $conditions[$key]['wid'] = $item['wid'];
            $conditions[$key]['arrival_date'] = $item['arrival_date'];
            $conditions[$key]['is_futures'] = $item['is_futures'];
            $conditions[$key]['quantity'] = $item['pay_quantity'];
        }

        $ProductInventory = new ProductInventory();
        $inventory = $ProductInventory->inventory($conditions);

        /* 发生错误 */
        if ($inventory['code'] === 1) {
            return $inventory;
        }

        foreach ($inventory['data'] as $key => $item) {
            if ($item['exceed_quantity'] !== 0) {
                return ['code' => 1, 'message' => '數量超過庫存'];
            }
        }

        $inventoryData = [];
        foreach ($inventory['data'] as $item) {
            $inventoryData[implode('_', [
                $item['productid'],
                $item['wid'],
                $item['arrival_date'],
                $item['is_futures']
            ])] = $item;
        }

        foreach ($productList as $key => &$item) {
            $inventory_key =  implode('_', [
                $item['product_id'],
                $item['wid'],
                $item['arrival_date'],
                $item['is_futures']
            ]);
            $param['list'][$key]['inventory'] = $inventoryData[$inventory_key];
        }

        Db::startTrans();
        try {

            // 查询用户
            $oCustomerModel = CustomerModel::where('id', $param['user_id'])->find();
            if (!$oCustomerModel) {
                throw new Exception("用户不存在！");
            }

            $total_amount = 0;
            $total_original_amount = 0;
            $total_first_leg_logistics_fee = 0; // 头程物流费
            foreach ($param['list'] as $value) {

                $value['original_actual_selling_price'] = $this->getProductOriginalPrice($oCustomerModel->role, $value, $value['actual_quoted_currency']);
                //商品金额
                $total_amount = bcadd($total_amount, (bcmul((string)($value['actual_selling_price'] ?? '0'), (string)($value['pay_quantity'] ?? '0'), 2)), 2);
                $total_original_amount = bcadd($total_original_amount, (bcmul((string)($value['original_actual_selling_price'] ?? '0'), (string)($value['pay_quantity'] ?? '0'), 2)), 2);
                $total_first_leg_logistics_fee = bcadd(
                    $total_first_leg_logistics_fee,
                    bcmul((string)($value['first_leg_logistics_fee'] ?? '0'), (string)($value['pay_quantity'] ?? '0'), 2),
                    2
                );
            }

            // 新建order
            $oOrderModel = new OrderModel();
            $oCommon = new Common();

            if (isset($param['order_no']) && $param['order_no']) {
                $orderno = $param['order_no'];
            } else {
                $orderno = $oCommon->generateOrderNoNew($param['contract_type'], $param['owner']);
            }
            $oOrderModel->order_no = $orderno;
            $oOrderModel->user_id = $param['user_id'];
            $oOrderModel->order_type = 1;
            $oOrderModel->delivery_method = $param['delivery_method'];
            // $oOrderModel->review_node = 4;
            $oOrderModel->currency = $param['currency'];
            $oOrderModel->order_remark = $param['order_remark'];
            $oOrderModel->source = $param['source'];
            $oOrderModel->is_sop = $param['is_sop']; // 是否拼单采购(Single Order Procurement) 0 - 否 1 - 是

            /* 添加账单地址 */
            if (!empty($param['billing_address_id'])) {

                $billingAddress = AddressModel::where('id', $param['billing_address_id'])->find();
                if (!$billingAddress) {
                    throw new Exception("账单地址不存在！");
                }

                $oOrderModel->billing_address_id = $billingAddress->id;
                $oOrderModel->billing_first_name = $billingAddress->first_name;
                $oOrderModel->billing_last_name = $billingAddress->last_name;
                $oOrderModel->billing_email = $billingAddress->email;
                $oOrderModel->billing_phone = $billingAddress->phone;
                $oOrderModel->billing_country_id = $billingAddress->country_id;
                $oOrderModel->billing_city_id = $billingAddress->city_id;
                $oOrderModel->billing_country_name = $billingAddress->country_name;
                $oOrderModel->billing_city_name = $billingAddress->city_name;
                $oOrderModel->billing_zip_code = $billingAddress->zip_code;
                $oOrderModel->billing_state = $billingAddress->state;
                $oOrderModel->billing_state_id = $billingAddress->state_id;
                $oOrderModel->billing_company = $billingAddress->company;
                $oOrderModel->billing_address = $billingAddress->address;
                $oOrderModel->billing_address2 = $billingAddress->address2;
                $oOrderModel->billing_remark = $billingAddress->remark;
            }


            if ($param['delivery_method'] == 1) {
                $oAddressModel = AddressModel::where('id', $param['address_id'])->find();
                if (!$oAddressModel) {
                    throw new Exception("地址不存在！");
                }
                $oOrderModel->first_name = $oAddressModel->first_name;
                $oOrderModel->last_name = $oAddressModel->last_name;
                $oOrderModel->email = $oAddressModel->email;
                $oOrderModel->phone = $oAddressModel->phone;
                $oOrderModel->country_id = $oAddressModel->country_id;
                $oOrderModel->city_id = $oAddressModel->city_id;
                $oOrderModel->country_name = $oAddressModel->country_name;
                $oOrderModel->city_name = $oAddressModel->city_name;
                $oOrderModel->zip_code = $oAddressModel->zip_code;
                $oOrderModel->state = $oAddressModel->state;
                $oOrderModel->state_id = $oAddressModel->state_id;
                $oOrderModel->company = $oAddressModel->company;
                $oOrderModel->address = $oAddressModel->address;
                $oOrderModel->address2 = $oAddressModel->address2;
                $oOrderModel->logistics_fee = $param['logistics_fee'];
                $oOrderModel->address_id = $param['address_id'];
                $oOrderModel->delivery_remark = $oAddressModel->remark;
            } else {
                $oWarehouseModel = WarehouseModel::where([['is_del', '=', 0], ['status', '=', 1], ['id', '=', $param['wid']]])->find();
                if (!$oWarehouseModel) {
                    throw new Exception("仓库不存在！");
                }
                $oOrderModel->pickup_address = $oWarehouseModel->pickup_address;
                $oOrderModel->pickup_name = $param['name'];
                $oOrderModel->pickup_phone = $param['phone'];
                $oOrderModel->pickup_passport = $param['passport'];
                $oOrderModel->annex = $param['annex'];
                if ($param['delivery_method'] == 2) {
                    $oOrderModel->warehouse_code = $param['warehouse_code'];
                }
                if ($param['delivery_method'] == 0) {
                    $oOrderModel->pickup_vehicle = $param['vehicle'];
                    $oOrderModel->pickup_code = generateUniqueString(6);
                }
            }
            $oOrderModel->first_leg_logistics_fee = $total_first_leg_logistics_fee;
            $oOrderModel->create_time = date('Y-m-d H:i:s');
            $oOrderModel->prescription = $param['prescription'];
            $oOrderModel->total_amount = $total_amount + $param['logistics_fee'] + $total_first_leg_logistics_fee;
            $oOrderModel->pay_amount = 0; // 已支付金额
            $oOrderModel->pay_status = 1;
            $oOrderModel->creator = $param['operator_id'];
            $oOrderModel->status = 10;
            $oOrderModel->product_total_amount = $total_amount;
            $oOrderModel->product_total_original_amount = $total_original_amount;
            $oOrderModel->delivery_terms = $param['delivery_terms'];

            $oOrderModel->pay_terms = $param['pay_terms'];
            $oOrderModel->advance_amount = $param['advance_amount'];

            $oOrderModel->signatory = $param['signatory'];
            $oOrderModel->signing_date = $param['signing_date'];
            $oOrderModel->single_order_method = $param['single_order_method'];
            $oOrderModel->id_number = $param['id_number'];
            $oOrderModel->payment_deadline = $param['payment_deadline'];
            $oOrderModel->shipping_start_date = $param['shipping_start_date'];

            if ($param['shipping_end_date']) {
                $oOrderModel->shipping_end_date = $param['shipping_end_date'];
            }
            $oOrderModel->transfer_payment_info = $param['transfer_payment_info'];
            $oOrderModel->contract_type = $param['contract_type'];
            $oOrderModel->owner = $param['owner'];
            $oOrderModel->partner = $param['partner'];
            $oOrderModel->order_remark = $param['order_remark'];
            $oOrderModel->notes = $param['notes'];
            $oOrderModel->order_num = array_sum(array_column($param['list'], 'pay_quantity'));
            if (!$oOrderModel->save()) {
                throw new Exception("订单创建失败！");
            }
            Log::info('主订单：' . json_encode($oOrderModel->toArray(), JSON_UNESCAPED_UNICODE));

            $insert_item_data = [];
            foreach ($param['list'] as $item) {

                $original_price = $this->getProductOriginalPrice($oCustomerModel->role, $item, $item['actual_quoted_currency']); // 获取产品原价 经销商原价就是一级折扣价格

                $insert_item_data[] = [
                    'user_id' => $param['user_id'],
                    'order_id' => $oOrderModel->id,
                    'product_id' => $item['product_id'],
                    'warehouse_id' => $item['wid'],
                    'original_price' => $original_price,
                    'actual_price' => $item['original_actual_price'],
                    'quantity' => $item['pay_quantity'],
                    'creator' => $param['operator_id'],
                    'create_time' => date('Y-m-d H:i:s'),
                    'pending_quantity' => $item['pay_quantity'],
                    'arrival_date' => $item['arrival_date'],
                    'real_arrival_date' => $item['real_arrival_date'],
                    'is_futures' => $item['is_futures'],
                    'transaction_currency_id' => $item['actual_quoted_currency'],
                    'price_selected_currency' => $item['actual_selling_price'],
                    'purchase_currency' => $item['inventory']['items'][0]['purchase_currency'],
                    'purchase_price' => $item['inventory']['items'][0]['purchase_price'],
                    'exceptionstatus' => $item['inventory']['exceptionstatus'],
                    'free_shipping' => $item['free_shipping'],
                    'apply_rules' => $item['apply_rules'],
                    'first_leg_logistics_fee' => $item['first_leg_logistics_fee']
                ];
            }

            $result = OrderItemModel::insertAll($insert_item_data);
            if (!$result) {
                throw new Exception("订单明细插入失败");
            }
            Log::info('订单行：' . json_encode($insert_item_data, JSON_UNESCAPED_UNICODE));
            // 更新客户表
            if ($oCustomerModel->stage != 3 && $oCustomerModel->stage != 2) {
                $oCustomerModel->stage = 2;
                if (!$oCustomerModel->save()) {
                    throw new Exception("客户表更新失败");
                }
            }

            //锁定库存 新版本下单无需锁定库存
            $this->logger->logOperation($oOrderModel->id, 'order', '订单-创建', '普通订单创建');

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            return ['code' => 1, 'message' => $e->getMessage()];
        }
        return ['code' => 0, 'message' => '订单创建成功！'];
    }


    /**
     * 获取产品原价 经销商原价是一级折扣价格
     * @param $role
     * @param $product
     * @return float
     */
    private function getProductOriginalPrice($role, $product, $transactionCurrencyId)
    {
        $inventoryInfo = InventoryModel::getInventoryInfoByFourElements($product['arrival_date'], $product['wid'], $product['is_futures'], $product['product_id']);

        $price = PriceModel::getPriceFromInventory($inventoryInfo['id'], $product['wid'], $transactionCurrencyId);

        $original_price = array_reduce($price['discount'], function ($carry, $item) {
            return $item['level'] == 1 ? $item['price'] : $carry;
        }, 0);

        if ($role == 'distributor') {
            return $original_price;
        } else {
            return $product['original_price'];
        }
    }

    /**
     * 订单修改
     * @param $param
     * @return array
     * 2024-11-21 13 57 48
     * author: jiang
     */
    public function update($param)
    {
        Db::startTrans();
        try {
            $total_amount = 0;
            $total_original_amount = 0;
            $total_first_leg_logistics_fee = 0; // 头程物流费
            $product_list = [];
            $oOrderModel = OrderModel::with('items')->where([['is_del', '=', 0], ['id', '=', $param['id']]])
                ->whereIn('status', [10, 30, 40])->where('review_node', 0)->find();
            if (!$oOrderModel) {
                throw new Exception("订单不存在或当前订单状态不允许修改！");
            }

            // +++ 新增：经销商订单拦截 +++ [1](@ref)
            if ($oOrderModel->order_type == 2) {
                throw new Exception("经销商发货订单不允许修改");
            }

            $originalOrder = clone $oOrderModel;
            $redis = new RedisClient();
            $key = 'update_original_data_id:' . $oOrderModel->id;
            $redis->set($key, json_encode($oOrderModel->toArray()));
            // +++ 新增：获取已发货数量 +++ [3](@ref)
            $shippedQtys = $this->getShippedQtys($oOrderModel->id);
            $customerInfo = CustomerModel::where('id', $oOrderModel->user_id)->find();

            foreach ($param['list'] as $value) {
                // +++ 商品数量校验 +++ [8](@ref)
                $key = $value['product_id'] . '_' . $value['wid'];
                $shippedQty = $shippedQtys[$key] ?? 0;
                if ($value['pay_quantity'] < $shippedQty) {
                    throw new Exception("商品数量不能小于已发货量($shippedQty)");
                }

                $value['original_actual_selling_price'] = $this->getProductOriginalPrice($customerInfo->role, $value, $value['actual_quoted_currency']);

                //商品金额
                $total_amount = bcadd($total_amount, (bcmul((string)($value['actual_selling_price'] ?? '0'), (string)($value['pay_quantity'] ?? '0'), 2)), 2);
                $total_original_amount = bcadd($total_original_amount, (bcmul((string)($value['original_actual_selling_price'] ?? '0'), (string)($value['pay_quantity'] ?? '0'), 2)), 2);
                $total_first_leg_logistics_fee = bcadd(
                    $total_first_leg_logistics_fee,
                    bcmul((string)($value['first_leg_logistics_fee'] ?? '0'), (string)($value['pay_quantity'] ?? '0'), 2),
                    2
                );
                $product_list[] = [
                    'id' => $value['product_id'],
                    'number' => $value['pay_quantity']
                ];
            }

            // +++ 金额校验 +++ [9](@ref)
            $newTotalAmount = $total_amount + $param['logistics_fee'] + $total_first_leg_logistics_fee;
            if ($newTotalAmount < $oOrderModel->pay_amount) {
                throw new Exception("订单金额不能小于已付款金额");
            }

            $oOrderModel->delivery_method = $param['delivery_method'];
            $oOrderModel->order_remark = $param['order_remark'];




            /* 添加账单地址 */
            if (!empty($param['billing_address_id'])) {

                $billingAddress = AddressModel::where('id', $param['billing_address_id'])->find();
                if (!$billingAddress) {
                    throw new Exception("账单地址不存在！");
                }

                $oOrderModel->billing_address_id = $billingAddress->id;
                $oOrderModel->billing_first_name = $billingAddress->first_name;
                $oOrderModel->billing_last_name = $billingAddress->last_name;
                $oOrderModel->billing_email = $billingAddress->email;
                $oOrderModel->billing_phone = $billingAddress->phone;
                $oOrderModel->billing_country_id = $billingAddress->country_id;
                $oOrderModel->billing_city_id = $billingAddress->city_id;
                $oOrderModel->billing_country_name = $billingAddress->country_name;
                $oOrderModel->billing_city_name = $billingAddress->city_name;
                $oOrderModel->billing_zip_code = $billingAddress->zip_code;
                $oOrderModel->billing_state = $billingAddress->state;
                $oOrderModel->billing_state_id = $billingAddress->state_id;
                $oOrderModel->billing_company = $billingAddress->company;
                $oOrderModel->billing_address = $billingAddress->address;
                $oOrderModel->billing_address2 = $billingAddress->address2;
                $oOrderModel->billing_remark = $billingAddress->remark;
            }


            if ($param['delivery_method'] == 1) {
                $oAddressModel = AddressModel::where('id', $param['address_id'])->find();
                if (!$oAddressModel) {
                    throw new Exception("地址不存在！");
                }

                // 运费
                $from_param = [
                    'shipping_warehouse' => $param['wid'],
                    'terms' => $param['delivery_terms'],
                    'to_nation' => $oAddressModel->country_id,
                    'prescription' => $param['prescription'],
                    'product_list' => $product_list
                ];

                $ServiceLogisticsRules = new AdminServiceLogisticsRules();
                $oOrderModel->first_name = $oAddressModel->first_name;
                $oOrderModel->last_name = $oAddressModel->last_name;
                $oOrderModel->email = $oAddressModel->email;
                $oOrderModel->phone = $oAddressModel->phone;
                $oOrderModel->country_id = $oAddressModel->country_id;
                $oOrderModel->city_id = $oAddressModel->city_id;
                $oOrderModel->country_name = $oAddressModel->country_name;
                $oOrderModel->city_name = $oAddressModel->city_name;
                $oOrderModel->zip_code = $oAddressModel->zip_code;
                $oOrderModel->state = $oAddressModel->state;
                $oOrderModel->company = $oAddressModel->company;
                $oOrderModel->address = $oAddressModel->address;
                $oOrderModel->address2 = $oAddressModel->address2;
                $oOrderModel->logistics_fee = $param['logistics_fee'];
                $oOrderModel->address_id = $param['address_id'];
                $oOrderModel->delivery_remark = $oAddressModel->remark;
            } else {
                $oOrderModel->pickup_name = $param['name'];
                $oOrderModel->pickup_phone = $param['phone'];
                $oOrderModel->pickup_passport = $param['passport'];
                $oOrderModel->annex = $param['annex'];
                if ($param['delivery_method'] == 0) {
                    $oOrderModel->pickup_vehicle = $param['vehicle'];
                }
                if ($param['delivery_method'] == 2) {
                    $oOrderModel->warehouse_code = $param['warehouse_code'];
                }
            }

            // +++ 支付状态处理 +++ [10](@ref)
            $status = $oOrderModel->status;
            $review_node = '';
            $job = null;
            if (in_array($oOrderModel->pay_status, [3, 4])) {
                $status = 20;
                $review_node = 2;
                $job = '1,10';

            }
            if ($review_node) {
                $oOrderModel->review_node = $review_node;
            }
            $order_no = '';
            if (isset($param['order_no']) && $param['order_no']) {
                $order_no = $param['order_no'];
            }
            $oOrderModel->source = $param['source'];
            $oOrderModel->is_sop = $param['is_sop']; // 是否拼单采购(Single Order Procurement) 0 - 否 1 - 是
            if ($order_no) {
                $oOrderModel->order_no = $order_no;
            }
            $pay_status = $originalOrder->pay_status;
            if ($originalOrder->pay_amount > 0 && $newTotalAmount <= $originalOrder->pay_amount) {
                $pay_status = 3;
            } elseif ($originalOrder->pay_amount > 0 && $newTotalAmount > $originalOrder->pay_amount) {
                $pay_status = 4;
            }
            $oOrderModel->prescription = $param['prescription'];
            $oOrderModel->first_leg_logistics_fee = $total_first_leg_logistics_fee;
            $oOrderModel->total_amount = $newTotalAmount;
            $oOrderModel->pay_amount = $originalOrder->pay_amount;
            $oOrderModel->pay_status = $pay_status;
            $oOrderModel->updater = $param['operator_id'];
            $oOrderModel->update_time = date('Y-m-d H:i:s');
            $oOrderModel->status = $status; // +++ 设置新状态 +++
            $oOrderModel->product_total_amount = $total_amount;
            $oOrderModel->product_total_original_amount = $total_original_amount;
            // $oOrderModel->review_node = 2;
            $oOrderModel->delivery_terms = $param['delivery_terms'];
            $oOrderModel->pay_terms = $param['pay_terms'];
            $oOrderModel->advance_amount = $param['advance_amount'];
            // ERP 3.1 bobo 修改 start
            $oOrderModel->currency = $param['currency'];
            $oOrderModel->notes = $param['notes'];
            $oOrderModel->order_remark = $param['order_remark'];
            $oOrderModel->signatory = $param['signatory'];
            $oOrderModel->signing_date = $param['signing_date'];
            $oOrderModel->owner = $param['owner'];
            $oOrderModel->partner = $param['partner'];
            $oOrderModel->single_order_method = $param['single_order_method'];
            $oOrderModel->id_number = $param['id_number'];
            $oOrderModel->payment_deadline = $param['payment_deadline'];
            $oOrderModel->shipping_start_date = $param['shipping_start_date'];
            if ($param['shipping_end_date']) {
                $oOrderModel->shipping_end_date = $param['shipping_end_date'];
            }

            $oOrderModel->transfer_payment_info = $param['transfer_payment_info'];
            $oOrderModel->contract_type = $param['contract_type'];
            $oOrderModel->order_num = array_sum(array_column($param['list'], 'pay_quantity'));

            if (2 == $oOrderModel->order_type) { // 经销商发货订单 产品总价为0 订单总价等于运费
                $oOrderModel->total_amount = $oOrderModel->logistics_fee;
                $oOrderModel->product_total_amount = 0;
            }

            // ERP 3.1 bobo 修改 end
            if (!$oOrderModel->save()) {
                throw new Exception("订单创建失败！");
            }



            $item_ids = [];
            $ins_data = [];
            $up_data = [];
            foreach ($param['list'] as $key => $item) {
                // +++ 重算待发数量 +++ [3](@ref)
                $key = $item['product_id'] . '_' . $item['wid'];
                $shippedQty = $shippedQtys[$key] ?? 0;

                $original_price = $this->getProductOriginalPrice($customerInfo->role, $item, $item['actual_quoted_currency']);

                /* 修改 */
                if (isset($item['order_item_id'])) {
                    $up_data = [
                        'id' => $item['order_item_id'],
                        'user_id' => $param['user_id'],
                        'order_id' => $oOrderModel->id,
                        'product_id' => $item['product_id'],
                        'warehouse_id' => $item['wid'],
                        'original_price' => $original_price,
                        'actual_price' => $item['original_actual_price'],
                        'quantity' => $item['pay_quantity'],
                        'pending_quantity' => $item['pay_quantity'] - $shippedQty, // +++ 修改 +++
                        'creator' => $param['operator_id'],
                        'create_time' => date('Y-m-d H:i:s'),
                        'arrival_date' => $item['arrival_date'],
                        'real_arrival_date' => $item['real_arrival_date'],
                        'is_futures' => $item['is_futures'],
                        'transaction_currency_id' => $item['actual_quoted_currency'],
                        'price_selected_currency' => $item['actual_selling_price'],
                        'free_shipping' => $item['free_shipping'],
                        'apply_rules' => $item['apply_rules'],
                        'first_leg_logistics_fee' => $item['first_leg_logistics_fee']
                    ];

                    $item_ids[] = $item['order_item_id'];

                    OrderItemModel::update($up_data);
                } else {
                    $ins_data[] = [
                        'user_id' => $param['user_id'],
                        'order_id' => $oOrderModel->id,
                        'product_id' => $item['product_id'],
                        'warehouse_id' => $item['wid'],
                        'original_price' => $original_price,
                        'actual_price' => $item['original_actual_price'],
                        'quantity' => $item['pay_quantity'],
                        'pending_quantity' => $item['pay_quantity'],
                        'creator' => $param['operator_id'],
                        'create_time' => date('Y-m-d H:i:s'),
                        'arrival_date' => $item['arrival_date'],
                        'real_arrival_date' => $item['real_arrival_date'],
                        'is_futures' => $item['is_futures'],
                        'transaction_currency_id' => $item['actual_quoted_currency'],
                        'price_selected_currency' => $item['actual_selling_price'],
                        'free_shipping' => $item['free_shipping'],
                        'apply_rules' => $item['apply_rules'],
                        'first_leg_logistics_fee' => $item['first_leg_logistics_fee']
                    ];
                }
            }

            Log::info(' [order_update] 待删除订单行id ：' . json_encode($item_ids));
            /* 去除已删掉的 item */
            $DelOrderItem = OrderItemModel::where('order_id', $oOrderModel->id);
            if (count($item_ids) > 0) {
                $DelOrderItem =  $DelOrderItem->whereNotIn('id', $item_ids);
            }
            $toDelete = $DelOrderItem->select();
            Log::info('  [order_update]  待删除订单行详情：' . json_encode($toDelete->toArray()));
            Log::info(' [order_update]  已发货信息：' . json_encode($shippedQtys));
            // +++ 删除前检查已发货量 +++ [8](@ref)
            foreach ($toDelete as $item) {
                $key = $item['product_id'] . '_' . $item['warehouse_id'];
                $shippedQty = $shippedQtys[$key] ?? 0;
                if ($shippedQty > 0) {
                    throw new Exception("包含已发货商品不可删除");
                }
            }
            if (count($item_ids) > 0) {
                $DelOrderItem->whereNotIn('id', $item_ids)->update(['is_del' => time()]);
            } else {
                $DelOrderItem->update(['is_del' => time()]);
            }

            /* 新增 Item  */
            if (count($ins_data) > 0) {
                OrderItemModel::insertAll($ins_data);
            }


            // 添加完之后 再锁定库存 新版本下单无需锁定库存
            // $apiOrder = new Inventory();
            // $apiOrder->Inventorylocking($oOrderModel, 'order');
            $this->logger->logOperation($oOrderModel->id, 'order', '订单-编辑', '修改普通订单',1,'order',$oOrderModel->id,$job);
            Db::commit();

            // 通知
            if (in_array($oOrderModel->pay_status, [3, 4])) {
                // 处理客户变更通知
                $notifications = [];
                $customer = CustomerModel::where('id', $oOrderModel->user_id)->find();
                $customerPartner = $customer->partner ? array_filter(explode(',', $customer->partner)) : [];
                $orderPartnerNew = $oOrderModel->partner ? array_filter(explode(',', $oOrderModel->partner)) : [];
                $orderPartnerOld = $originalOrder['partner'] ? array_filter(explode(',', $originalOrder['partner'])) : [];
                $recipients = array_filter(array_unique([$customer->owner, $oOrderModel->owner, $originalOrder['owner'], $oOrderModel->signatory, ...$customerPartner, ...$orderPartnerNew, ...$orderPartnerOld]));

                // 负责人变更通知w
                if ($oOrderModel->owner != $originalOrder['owner']) {
                    if ($originalOrder['owner'] == 0) {
                        // 添加负责人
                        $notifications[] = ['event' => 'order_owner_allocated', 'recipients' => $recipients, 'log' => '订单添加负责人通知发送失败'];
                    } else {
                        // 变更负责人 - 通知新负责人和原负责人
                        $notifications[] = ['event' => 'order_owner_allocated', 'recipients' => $recipients, 'log' => '订单变更负责人通知发送失败'];
                        $notifications[] = ['event' => 'order_owner_transfer', 'recipients' => $recipients, 'log' => '订单变更负责人通知发送失败'];
                    }
                }

                // 合作伙伴变更通知
                if ($oOrderModel->partner != $originalOrder['partner']) {
                    $notifications[] = ['event' => 'order_partner_transfer', 'recipients' => $recipients, 'log' => '订单合作伙伴变更通知发送失败'];
                }

                $notifications[] = ['event' => 'order_edit', 'recipients' => $recipients, 'log' => '订单修改通知发送失败'];
                if ($oOrderModel->status == 20) {
                    $notifications[] = ['event' => 'order_audit', 'recipients' => [], 'log' => '订单待审核发送失败', 'job' => '1,10'];
                }
                if (!empty($notifications)) {
                    $notificationService = new CompleteNotificationService();
                    foreach ($notifications as $notification) {
                        try {
                            $notificationService->send($notification['event'], $oOrderModel->toArray(), $notification['recipients'], '', $notification['job'] ?? '');
                        } catch (\Exception $e) {
                            Log::error($notification['log'] . ': ' . $e->getMessage() . ' 订单编号: ' . $oOrderModel->order_no . ' | 文件：' . $e->getFile() . ' | 行号：' . $e->getLine());
                        }
                    }
                }
            }

        } catch (\Exception $e) {
            Db::rollback();
            return ['code' => 1, 'message' => $e->getMessage()];
        }
        return ['code' => 0, 'message' => '订单修改成功！'];
    }

    // +++ 新增：获取已发货数量方法 +++ [3](@ref)
    private function getShippedQtys($orderId)
    {
        $shippedData = Db::name('logistics_order_item')
            ->alias('loi')
            ->join('logistics_order lo', 'loi.logistics_order_id = lo.id')
            ->where('loi.order_id', $orderId)
            ->where('lo.type', 1)
            ->where('lo.status', 1)
            ->field('product_id, number as shipped_qty,warehouse_id')
            ->select();

        $result = [];

        foreach ($shippedData as $item) {
            $key = $item['product_id'] . '_' . $item['warehouse_id'];
            if (!isset($result[$key])) {
                $result[$key] = 0;
            }
            $result[$key] += $item['shipped_qty'];
        }

        return $result;
    }

    /**
     * 订单复制
     * @param int $id 订单ID
     * @return array
     */
    public function copy($param)
    {
        $where = [['is_del', '=', '0'], ['id', '=', $param['id']], ['order_type', '<>', 2]];
        $oOrderModel = OrderModel::where($where)->with(['items', 'payment',  'customer'])->find();
        if (!$oOrderModel) {
            return ['code' => 1, 'message' => '获取订单信息失败！'];
        }

        $oImages = new Images();

        // 格式化
        $formatData = [];
        $formatData['user'] = $oOrderModel->user . ' (' . $oOrderModel->user_email . ')';
        $formatData['user_id'] = $oOrderModel->user_id;
        $formatData['user_name'] = $oOrderModel->user;
        $formatData['user_email'] = $oOrderModel->user_email;
        $formatData['total_amount'] = $oOrderModel->total_amount;
        $formatData['product_total_original_amount'] = $oOrderModel->product_total_original_amount;
        $formatData['product_total_amount'] = $oOrderModel->product_total_amount;
        $formatData['pay_terms'] = $oOrderModel->pay_terms;
        $formatData['advance_amount'] = $oOrderModel->advance_amount;
        $formatData['delivery_method'] = $oOrderModel->delivery_method;
        $formatData['order_type'] = $oOrderModel->order_type;
        $formatData['address_id'] = $oOrderModel->address_id;
        $formatData['notes'] = $oOrderModel->notes;
        $formatData['order_remark'] = $oOrderModel->order_remark;
        $formatData['country_id'] = $oOrderModel->country_id;
        $formatData['create_time'] = $oOrderModel->create_time;
        $formatData['creator'] = $oOrderModel->creator;
        $formatData['update_time'] = $oOrderModel->update_time;
        $formatData['updater'] = $oOrderModel->updater;

        $formatData['signatory'] = $oOrderModel->signatory;
        $formatData['signing_date'] = $oOrderModel->signing_date;
        $formatData['single_order_method'] = $oOrderModel->single_order_method;
        $formatData['contract_type'] = $oOrderModel->contract_type;
        $formatData['currency'] = $oOrderModel->currency;
        $formatData['id_number'] = $oOrderModel->id_number;
        $formatData['payment_deadline'] = $oOrderModel->payment_deadline;
        $formatData['shipping_start_date'] = $oOrderModel->shipping_start_date;
        $formatData['shipping_end_date'] = $oOrderModel->shipping_end_date;
        $formatData['contract_type'] = $oOrderModel->contract_type;
        $formatData['transfer_payment_info'] = $oOrderModel->transfer_payment_info;
        $formatData['owner'] = $oOrderModel->owner;
        $formatData['partner'] = $oOrderModel->partner;
        $formatData['exceptionstatus'] = $oOrderModel->exceptionstatus;
        $formatData['order_category'] = $oOrderModel->order_category;
        $formatData['source'] = $oOrderModel->source;

        /* 账单地址 */
        $formatData['billing_address_id'] = $oOrderModel->billing_address_id;
        $formatData['edit']['billing_address_id'] = $oOrderModel->billing_address_id;
        if ($oOrderModel->billing_address_id) {
            $formatData['edit']['billing_address'] = $oOrderModel->billing_first_name . $oOrderModel->billing_last_name . ' ' . $oOrderModel->billing_phone . ' ' . $oOrderModel->billing_address;
        } else {
            $formatData['edit']['billing_address'] = null;
        }


        if ($formatData['creator']) $formatData['creator'] = Db::name('operator')->where('id', $formatData['creator'])->value('nickname');
        if ($formatData['updater'])  $formatData['updater'] = Db::name('operator')->where('id', $formatData['updater'])->value('nickname');

        $formatData['voucher'] = [];


        $formatData['edit']['name'] = $oOrderModel->pickup_name;
        $formatData['edit']['phone'] = $oOrderModel->pickup_phone;
        $formatData['edit']['passport'] = $oOrderModel->pickup_passport;
        $formatData['edit']['vehicle'] = $oOrderModel->pickup_vehicle;
        $formatData['edit']['warehouse_code'] = $oOrderModel->warehouse_code;
        $formatData['edit']['prescription'] = $oOrderModel->prescription;
        $formatData['edit']['delivery_terms'] = $oOrderModel->delivery_terms;
        $formatData['edit']['user_id'] = $oOrderModel->user_id;
        $formatData['edit']['email'] = $oOrderModel->user_email;
        $formatData['edit']['user'] = $oOrderModel->user;
        $formatData['edit']['delivery_method'] = $oOrderModel->delivery_method;
        $formatData['edit']['role'] = $oOrderModel->role;
        $formatData['edit']['address'] = $oOrderModel->address;
        $formatData['edit']['signatory'] = $oOrderModel->signatory;
        if ($formatData['edit']['signatory']) {
            $formatData['edit']['signatory_value'] = OrderModel::name('operator')->where('id', $oOrderModel->signatory)->column('cname')[0] ?? '';
        }
        $formatData['edit']['contract_type'] = $oOrderModel->contract_type;
        $formatData['edit']['transfer_payment_info'] = $oOrderModel->transfer_payment_info;
        $formatData['edit']['id_number'] = $oOrderModel->id_number;
        $formatData['edit']['payment_deadline'] = $oOrderModel->payment_deadline;
        $formatData['edit']['shipping_start_date'] = $oOrderModel->shipping_start_date;
        $formatData['edit']['shipping_end_date'] = $oOrderModel->shipping_end_date;
        $formatData['edit']['owner'] = $oOrderModel->owner;
        $formatData['edit']['partner'] = $oOrderModel->partner;
        $formatData['edit']['currency'] = $oOrderModel->currency;

        $formatData['list'] = [];
        $formatData['edit_list'] = [];
        $formatData['payment'] = [];


        if (214 != $oOrderModel->currency) {
            // 获取币种信息
            $currencyIds = [$oOrderModel->currency, 214]; // 客户选定的币种和美金
            $currencyData = Db::table('db_transaction_currency')
                ->whereIn('id', $currencyIds)
                ->field('abbr,name,id')
                ->select()
                ->toArray();
            $currencyData = array_column($currencyData, null, 'id');

            $customerPaymentCurrencyData = $currencyData[$oOrderModel->currency] ?? null;
            $usdCurrencyData = $currencyData[214] ?? null;
            $fetcher = new ExchangeRateHostAPI();
            $conversion_rate = $fetcher->getRate($usdCurrencyData['abbr'], $customerPaymentCurrencyData['abbr']);
            if (!is_numeric($conversion_rate)) {
                return ['code' => 1, 'message' => '汇率获取失败' . $conversion_rate];
            }
        } else {
            $conversion_rate = 0;
        }

        foreach ($oOrderModel->items as $value) {

            // 查询可售库存
            $available = Db::table('db_inventory')
                ->where([
                    'productid' => $value['product_id'],
                    'arrival_date' => $value['arrival_date'],
                    'is_futures' => $value['is_futures'],
                    'is_del' => 0,
                    'is_sale' => 1
                ])
                ->whereRaw('FIND_IN_SET(? , wid) > 0', [$value['warehouse_id']])
                ->field("SUM(available_qty) - SUM(lock_qty) as available_sum , MAX(allow_zero_stock_sale) as allow_zero_stock_sale")
                ->find();
            if ($available['allow_zero_stock_sale'] == 0 && $available['available_sum'] <= 0) {
                continue;
            }

            // 获取折扣
            $whereInv = [
                ['is_del', '=', '0'],
                ['productid', '=', $value['product_id']],
                ['wid', '=', $value['warehouse_id']],
                ['is_futures', '=', $value['is_futures']],
                ['arrival_date', '=', $value['arrival_date']]
            ];
            $oInventoryModel = InventoryModel::with(['product_price' => function ($query) use ($value) {
                // 这里添加 product_price 表的查询条件
                $query->where('transaction_currency_id', $value['transaction_currency_id']);
            }])->where($whereInv)->find();
            //            if (!$oInventoryModel) {
            //                continue;
            //            }




            $edit_data = [
                'order_item_id' => $value['id'],
                'product_id' => $value['product_id'],
                'arrival_date' => $value['arrival_date'],
                'real_arrival_date' => $value['real_arrival_date'],
                'is_futures' => $value['is_futures'],
                'wid' => $value['warehouse_id'],
                'product_name' => $value['product_name'],
                'product_code' => $value['code'],
                'expiration_date' => $value['expiration_date'],
                'brand' => $value['brand'],
                'hashrate' => $value['hashrate'] . $value['computing_unit'],
                'quantity' => $available['available_sum'] < 0 ? 0 : $available['available_sum'], // 可售库存 = 可用库存 - 锁定库存
                'allow_zero_stock_sale' => $available['allow_zero_stock_sale'],
                'original_price' => $value['original_price'],
                'actual_price' => $value['actual_price'],
                'free_shipping' => $value['free_shipping'],
                'billing_weight' => $value['billing_weight'],
                'apply_rules' => $value['apply_rules'],
                'original_actual_price' => $value['actual_price'],
                'pay_quantity' => $value['quantity'],
                'unique' => $value['product_id'] . '_' . $value['arrival_date'] . '_' . $value['is_futures'] . '_' . $value['warehouse_id'],
                'actual_quoted_currency' => $value['transaction_currency_id'],
                'actual_selling_price' => $value['price_selected_currency'],
                'original_actual_selling_price' => $value['price_selected_currency'],
                'first_leg_logistics_fee' => $value['first_leg_logistics_fee'],
                'actual_quoted_currency_name' =>   Db::table('db_transaction_currency')->where('id', $value['transaction_currency_id'])->field('name')->find()['name'], // 实际报价数据更改
                'fl_warehouse_id' => WarehouseModel::where('id', $value['warehouse_id'])->value('fl_warehouse_id')
            ];

            if (isset($oInventoryModel->product_price) && isset($oInventoryModel->product_price->discount)) {
                foreach ($oInventoryModel->product_price->discount as $discount) {
                    $edit_data['discount_price'][] = [
                        'num' => $discount['num'],
                        'rate' => $discount['rate'],
                        'price' => $discount['price'],
                        'level' => $discount['level'],
                        'discount_actual_selling_price' => $conversion_rate > 0 ? round($discount['price'] * $conversion_rate, 2) : $discount['price']
                    ];
                }
            } else {
                $edit_data['discount_price'] = [];
            }


            $formatData['edit_list'][] = $edit_data;
        }


        $formatData['pickup'] = [];
        $formatData['pickup'][] = [
            'pickup_address' => $oOrderModel->pickup_address,
            'pickup_code' => $oOrderModel->pickup_code,
            'pickup_name' => $oOrderModel->pickup_name,
            'pickup_phone' => $oOrderModel->pickup_phone,
            'pickup_passport' => $oOrderModel->pickup_passport,
            'pickup_vehicle' => $oOrderModel->pickup_vehicle,
            'warehouse_code' => $oOrderModel->warehouse_code,
            'annex' => $oOrderModel->annex,
            'annex_list' => $oImages->getImagesByIds($oOrderModel->annex ? explode(',', $oOrderModel->annex) : []),
        ];

        $formatData['delivery'] = [];


        $formatData['logistics'] = [];


        // 最终的格式化数据
        $orderItemType = [];
        foreach ($formatData['list'] as $item) { // 前台是否显示库存类型转换
            if (0 != $item['is_futures'] && $item['quantity'] > 0) {
                $orderItemType[] = $item['is_futures'];
            }
        }
        $formatData['show_entry'] = (in_array(1, $orderItemType) || in_array(2, $orderItemType)) && $oOrderModel->pay_status == 3 && $oOrderModel->review_node == 0; // 是否显示库存类型转换

        // 计算订单可部分发货金额
        $partDeliveryRatio = SystemConfigModel::where(['key' => 'PART_DELIVERY_PRODUCT_AMOUNT_RATIO'])->value('value');
        $formatData['part_delivery_amount'] = $oOrderModel->pay_amount * (floatval($partDeliveryRatio ?: 0) / 100);

        $formatData['current_serial_number'] = $this->getCurrenSerialNumber($oOrderModel); // 当前发货单号

        return ['code' => 0, 'message' => 'success', 'data' => $formatData];
    }
    /**
     * 获取单个订单信息
     * @param int $id 订单ID
     * @return array
     */
    public function cancelUpdate($param){
        $where = [['is_del', '=', '0'], ['id', '=', $param['id']],['status', '=',20],['creator','=',$param['operator_id']]];
        $oOrderModel = OrderModel::where($where)->with(['items', 'payment',  'customer', 'logger'])->find();
        if (!$oOrderModel) {
            return ['code' => 1, 'message' => '获取订单信息失败！'];
        }
        $redis = (new RedisClient())->getClient();
        $update = $this->rejectUpdateOrder($param['id']);
        if($update['code'] == 1){
            return $update;
        }
        $redis->del('update_original_data_id:' . $oOrderModel->id);
        $this->logger->logOperation($oOrderModel->id, 'order', '订单-撤销编辑', '修改普通订单');
        return ['code' => 0, 'message' => 'success'];

    }
    /**
     * 获取单个订单信息
     * @param int $id 订单ID
     * @return array
     */
    public function getInfo($param)
    {
        $where = [['is_del', '=', '0'], ['id', '=', $param['id']]];
        $oOrderModel = OrderModel::where($where)->with(['items', 'payment',  'customer', 'logger'])->find();
        if (!$oOrderModel) {
            return ['code' => 1, 'message' => '获取订单信息失败！'];
        }

        // 如果是待支付且部分支付状态，获取部分发货申请的待发数量
        $pendingQuantities = [];
        if ($oOrderModel->status == 10 && $oOrderModel->pay_status == 4) {
            $pendingQuantities = Db::name('order_part_delivery_apply_item')
                ->alias('item')
                ->join('order_part_delivery_apply apply', 'item.order_part_delivery_apply_id = apply.id')
                ->where([
                    ['apply.order_id', '=', $oOrderModel->id],
                    ['item.is_del', '=', 0],
                    ['apply.is_del', '=', 0],
                    ['apply.status', '=', 2]
                ])
                ->group('item.order_item_id')
                ->column('sum(item.pending_quantity) as total', 'item.order_item_id');
        }

        $oImages = new Images();

        // 格式化
        $formatData = [];
        $formatData['user'] = $oOrderModel->user . ' (' . $oOrderModel->user_email . ')';
        $formatData['user_id'] = $oOrderModel->user_id;
        $formatData['user_name'] = $oOrderModel->user;
        $formatData['user_email'] = $oOrderModel->user_email;
        $formatData['total_amount'] = $oOrderModel->total_amount;
        $formatData['product_total_original_amount'] = $oOrderModel->product_total_original_amount;
        $formatData['product_total_amount'] = $oOrderModel->product_total_amount;
        $formatData['pay_terms'] = $oOrderModel->pay_terms;
        $formatData['advance_amount'] = $oOrderModel->advance_amount;
        $formatData['pay_amount'] = $oOrderModel->pay_amount;
        $formatData['delivery_method'] = $oOrderModel->delivery_method;
        $formatData['logistics_fee'] = $oOrderModel->logistics_fee;
        $formatData['first_leg_logistics_fee'] = $oOrderModel->first_leg_logistics_fee;
        $formatData['order_no'] = $oOrderModel->order_no;
        $formatData['order_type'] = $oOrderModel->order_type;
        $formatData['order_status'] = $oOrderModel->status;
        $formatData['pay_status'] = $oOrderModel->pay_status;
        $formatData['aftersales_status'] = $oOrderModel->aftersales_status;
        $formatData['address_id'] = $oOrderModel->address_id;
        $formatData['review_node'] = $oOrderModel->review_node;
        $formatData['notes'] = $oOrderModel->notes;
        $formatData['order_remark'] = $oOrderModel->order_remark;
        $formatData['logger'] = $oOrderModel->logger;
        $formatData['country_id'] = $oOrderModel->country_id;
        $formatData['create_time'] = $oOrderModel->create_time;
        $formatData['creator'] = $oOrderModel->creator;
        $formatData['creator_id'] = $oOrderModel->creator;
        $formatData['update_time'] = $oOrderModel->update_time;
        $formatData['updater'] = $oOrderModel->updater;

        $formatData['signatory'] = $oOrderModel->signatory;
        $formatData['signing_date'] = $oOrderModel->signing_date;
        $formatData['single_order_method'] = $oOrderModel->single_order_method;
        $formatData['contract_type'] = $oOrderModel->contract_type;
        $formatData['currency'] = $oOrderModel->currency;
        $formatData['id_number'] = $oOrderModel->id_number;
        $formatData['payment_deadline'] = $oOrderModel->payment_deadline;
        $formatData['shipping_start_date'] = $oOrderModel->shipping_start_date;
        $formatData['shipping_end_date'] = $oOrderModel->shipping_end_date;
        $formatData['contract_type'] = $oOrderModel->contract_type;
        $formatData['transfer_payment_info'] = $oOrderModel->transfer_payment_info;
        $formatData['owner'] = $oOrderModel->owner;
        $formatData['partner'] = $oOrderModel->partner;
        $formatData['exceptionstatus'] = $oOrderModel->exceptionstatus;
        $formatData['order_category'] = $oOrderModel->order_category;
        $formatData['source'] = $oOrderModel->source;
        $formatData['is_sop'] = $oOrderModel->is_sop; // 是否拼单采购(Single Order Procurement) 0 - 否 1 - 是

        /* 账单地址 */
        $formatData['billing_address_id'] = $oOrderModel->billing_address_id;
        $formatData['edit']['billing_address_id'] = $oOrderModel->billing_address_id;
        if ($oOrderModel->billing_address_id) {
            $formatData['edit']['billing_address'] = $oOrderModel->billing_first_name . $oOrderModel->billing_last_name . ' ' . $oOrderModel->billing_phone . ' ' . $oOrderModel->billing_address;
        } else {
            $formatData['edit']['billing_address'] = null;
        }


        if ($formatData['creator']) $formatData['creator'] = Db::name('operator')->where('id', $formatData['creator'])->value('nickname');
        if ($formatData['updater'])  $formatData['updater'] = Db::name('operator')->where('id', $formatData['updater'])->value('nickname');
        if ($oOrderModel->voucher) {
            $img_arr = explode(',', $oOrderModel->voucher);
            $oImages = new Images();
            $imgObject = $oImages->getImagesByIds($img_arr);
            foreach ($imgObject as $img) {
                $formatData['voucher'][] = $img['url'];
            }
        } else {
            $formatData['voucher'] = [];
        }

        $formatData['edit']['name'] = $oOrderModel->pickup_name;
        $formatData['edit']['phone'] = $oOrderModel->pickup_phone;
        $formatData['edit']['passport'] = $oOrderModel->pickup_passport;
        $formatData['edit']['vehicle'] = $oOrderModel->pickup_vehicle;
        $formatData['edit']['warehouse_code'] = $oOrderModel->warehouse_code;
        $formatData['edit']['address'] = $oOrderModel->address;
        $formatData['edit']['prescription'] = $oOrderModel->prescription;
        $formatData['edit']['delivery_terms'] = $oOrderModel->delivery_terms;
        $formatData['edit']['user_id'] = $oOrderModel->user_id;
        $formatData['edit']['email'] = $oOrderModel->user_email;
        $formatData['edit']['user'] = $oOrderModel->user;
        $formatData['edit']['delivery_method'] = $oOrderModel->delivery_method;
        $formatData['edit']['logistics_fee'] = $oOrderModel->logistics_fee;
        $formatData['edit']['first_leg_logistics_fee'] = $oOrderModel->first_leg_logistics_fee;
        $formatData['edit']['role'] = $oOrderModel->role;

        $formatData['edit']['signatory'] = $oOrderModel->signatory;
        if ($formatData['edit']['signatory']) {
            $formatData['edit']['signatory_value'] = OrderModel::name('operator')->where('id', $oOrderModel->signatory)->column('cname')[0] ?? '';
        }
        $formatData['edit']['contract_type'] = $oOrderModel->contract_type;
        $formatData['edit']['transfer_payment_info'] = $oOrderModel->transfer_payment_info;
        $formatData['edit']['id_number'] = $oOrderModel->id_number;
        $formatData['edit']['payment_deadline'] = $oOrderModel->payment_deadline;
        $formatData['edit']['shipping_start_date'] = $oOrderModel->shipping_start_date;
        $formatData['edit']['shipping_end_date'] = $oOrderModel->shipping_end_date;
        $formatData['edit']['owner'] = $oOrderModel->owner;
        $formatData['edit']['partner'] = $oOrderModel->partner;
        $formatData['edit']['currency'] = $oOrderModel->currency;

        $formatData['list'] = [];
        $formatData['edit_list'] = [];
        $formatData['payment'] = [];


        if (214 != $oOrderModel->currency) {
            // 获取币种信息
            $currencyIds = [$oOrderModel->currency, 214]; // 客户选定的币种和美金
            $currencyData = Db::table('db_transaction_currency')
                ->whereIn('id', $currencyIds)
                ->field('abbr,name,id')
                ->select()
                ->toArray();
            $currencyData = array_column($currencyData, null, 'id');

            $customerPaymentCurrencyData = $currencyData[$oOrderModel->currency] ?? null;
            $usdCurrencyData = $currencyData[214] ?? null;
            $fetcher = new ExchangeRateHostAPI();
            $conversion_rate = $fetcher->getRate($usdCurrencyData['abbr'], $customerPaymentCurrencyData['abbr']);
            if (!is_numeric($conversion_rate)) {
                return ['code' => 1, 'message' => '汇率获取失败' . $conversion_rate];
            }
        } else {
            $conversion_rate = 0;
        }

        foreach ($oOrderModel->items as $value) {
            $key = implode('_', [
                $value['product_id'],
                $value['warehouse_id'],
                $value['arrival_date'],
                $value['is_futures']
            ]);

            $fl_warehouse_id = null;
            if (isset($value['warehouses'])) {
                $fl_warehouse_id = $value['warehouses']['fl_warehouse_id'];
            }
            $wholesal_info = [];
            if ($oOrderModel->order_type == 2 && $value['wholesal_id']) {
                $wholesal_info = \app\admin\model\Order::where('id', $value['wholesal_id'])->field('id,order_no')->find();
            }

            $formatData['list'][] = [
                'id' => $value['id'],
                'wid' => $value['warehouse_id'],
                'wholesal_id' => $value['wholesal_id'],
                'fl_warehouse_id' => $fl_warehouse_id,
                'code' => $value['code'],
                'name' => 0 != $value['product_id'] ? $value['product_name'] : $value['product_abbr'],
                'hashrate' => $value['hashrate'],
                'expiration_date' => $value['expiration_date'],
                'is_futures' => $value['is_futures'],
                'arrival_date' => $value['arrival_date'],
                'real_arrival_date' => $value['real_arrival_date'],
                'original_price' => $value['original_price'],
                'actual_price' => $value['actual_price'],
                'free_shipping' => $value['free_shipping'],
                'apply_rules' => $value['apply_rules'],
                'quantity' => $value['quantity'],
                'brand' => $value['brand'],
                'wholesal_no' => $wholesal_info['order_no'] ?? '',
                'product_id' => $value['product_id'],
                'pending_quantity' => $oOrderModel->status == 10 && $oOrderModel->pay_status == 4 && count($pendingQuantities) > 0  && array_sum($pendingQuantities) > 0 ?
                    ($pendingQuantities[$value['id']] ?? 0) : $value['pending_quantity'],
                'actual_quoted_currency' => $value['transaction_currency_id'],
                'actual_selling_price' => $value['price_selected_currency'],
                'first_leg_logistics_fee' => $value['first_leg_logistics_fee'],
                'actual_quoted_currency_name' => Db::table('db_transaction_currency')->where('id', $value['transaction_currency_id'])->field('name')->find()['name'],
                'exceptionstatus' => $value['exceptionstatus'],
                'remark' => $value['remark']
            ];

            // 获取折扣
            $whereInv = [
                ['is_del', '=', '0'],
                ['productid', '=', $value['product_id']],
                ['wid', '=', $value['warehouse_id']],
                ['is_futures', '=', $value['is_futures']],
                ['arrival_date', '=', $value['arrival_date']]
            ];
            $oInventoryModel = InventoryModel::with(['product_price' => function ($query) use ($value) {
                // 这里添加 product_price 表的查询条件
                $query->where('transaction_currency_id', $value['transaction_currency_id']);
            }])->where($whereInv)->find();
            //            if (!$oInventoryModel) {
            //                continue;
            //            }


            // 查询可售库存
            $available = Db::table('db_inventory')
                ->where([
                    'productid' => $value['product_id'],
                    'arrival_date' => $value['arrival_date'],
                    'is_futures' => $value['is_futures'],
                    'is_del' => 0,
                    'is_sale' => 1
                ])
                ->whereRaw('FIND_IN_SET(? , wid) > 0', [$value['warehouse_id']])
                ->field("SUM(available_qty) - SUM(lock_qty) as available_sum , MAX(allow_zero_stock_sale) as allow_zero_stock_sale")
                ->find();

            $edit_data = [
                'order_item_id' => $value['id'],
                'product_id' => $value['product_id'],
                'arrival_date' => $value['arrival_date'],
                'real_arrival_date' => $value['real_arrival_date'],
                'is_futures' => $value['is_futures'],
                'wid' => $value['warehouse_id'],
                'product_name' => $value['product_name'],
                'product_code' => $value['code'],
                'expiration_date' => $value['expiration_date'],
                'brand' => $value['brand'],
                'hashrate' => $value['hashrate'] . $value['computing_unit'],
                'quantity' => $available['available_sum'] < 0 ? 0 : $available['available_sum'], // 可售库存 = 可用库存 - 锁定库存
                'allow_zero_stock_sale' => $available['allow_zero_stock_sale'],
                'original_price' => $value['original_price'],
                'actual_price' => $value['actual_price'],
                'free_shipping' => $value['free_shipping'],
                'billing_weight' => $value['billing_weight'],
                'apply_rules' => $value['apply_rules'],
                'original_actual_price' => $value['actual_price'],
                'pay_quantity' => $value['quantity'],
                'unique' => $value['product_id'] . '_' . $value['arrival_date'] . '_' . $value['is_futures'] . '_' . $value['warehouse_id'],
                'actual_quoted_currency' => $value['transaction_currency_id'],
                'actual_selling_price' => $value['price_selected_currency'],
                'original_actual_selling_price' => $value['price_selected_currency'],
                'first_leg_logistics_fee' => $value['first_leg_logistics_fee'],
                'actual_quoted_currency_name' =>   Db::table('db_transaction_currency')->where('id', $value['transaction_currency_id'])->field('name')->find()['name'], // 实际报价数据更改
                'fl_warehouse_id' => WarehouseModel::where('id', $value['warehouse_id'])->value('fl_warehouse_id')
            ];

            if (isset($oInventoryModel->product_price) && isset($oInventoryModel->product_price->discount)) {
                foreach ($oInventoryModel->product_price->discount as $discount) {
                    $edit_data['discount_price'][] = [
                        'num' => $discount['num'],
                        'rate' => $discount['rate'],
                        'price' => $discount['price'],
                        'level' => $discount['level'],
                        'discount_actual_selling_price' => $conversion_rate > 0 ? round($discount['price'] * $conversion_rate, 2) : $discount['price']
                    ];
                }
            } else {
                $edit_data['discount_price'] = [];
            }


            $formatData['edit_list'][] = $edit_data;
        }

        if ($oOrderModel->payment) {
            $all_voucher_id = array_column($oOrderModel->payment->toArray(), 'transfer_voucher_id');
            $all_recepit_id = array_column($oOrderModel->payment->toArray(), 'transfer_recepit_id');
            $all_voucher_id = array_merge($all_voucher_id, $all_recepit_id);
            $all_voucher_id = implode(',', $all_voucher_id);
            $all_voucher_url = $oImages->getImagesByIds($all_voucher_id);
            if ($all_voucher_url) {
                $all_voucher_url = array_column($all_voucher_url, null, 'id');
            }
        }

        foreach ($oOrderModel->payment as $item) {
            if ($item['transfer_voucher_id']) {
                $item['transfer_voucher_id'] = array_reduce(explode(',', $item['transfer_voucher_id']), function ($carry, $item) use ($all_voucher_url) {
                    $carry[] = $all_voucher_url[$item] ?? '';
                    return $carry;
                }, []);
            }
            if ($item['transfer_recepit_id']) {
                $item['transfer_recepit_id'] = array_reduce(explode(',', $item['transfer_recepit_id']), function ($carry, $item) use ($all_voucher_url) {
                    $carry[] = $all_voucher_url[$item] ?? '';
                    return $carry;
                }, []);
            }

            $formatData['payment'][] = [
                'id' => $item['id'],
                'user_name' => $oOrderModel->user,
                'pay_account' => $item['pay_account'],
                'voucher_code' => $item['voucher_code'],
                'transfer_voucher_url' => $item['transfer_voucher_id'],
                'transfer_recepit_url' => $item['transfer_recepit_id'],
                'pay_code' => $item['pay_code'],
                'pay_currency' => $item['pay_currency'],
                'payment_url' => $item['payment_url'],
                'pay_time' => $item['pay_time'],
                'pay_amount' => $item['pay_amount'],
                'paid_amount' => $item['paid_amount'],
                'pay_status' => $item['status'],
                'notes' => $item['notes'],
                'remark' => $item['remark'],
                'reviewer' => $item['reviewer'],
                'reviewer_time' => $item['reviewer_time'],
                'pay_method' => $item['payment_method'],
                'order_no' => $oOrderModel->order_no,
                'order_type' => $item['order_type'],
                'payment_method' => $item['payment_method'],
                'fee_type' => $item['fee_type'],
                'transfer_type' => $item['transfer_type'],
                'order_total_amount' => $oOrderModel->total_amount,
                'order_pay_amount' => $oOrderModel->pay_amount
            ];
        }


        $formatData['pickup'] = [];
        $formatData['pickup'][] = [
            'pickup_address' => $oOrderModel->pickup_address,
            'pickup_code' => $oOrderModel->pickup_code,
            'pickup_name' => $oOrderModel->pickup_name,
            'pickup_phone' => $oOrderModel->pickup_phone,
            'pickup_passport' => $oOrderModel->pickup_passport,
            'pickup_vehicle' => $oOrderModel->pickup_vehicle,
            'warehouse_code' => $oOrderModel->warehouse_code,
            'annex' => $oOrderModel->annex,
            'annex_list' => $oImages->getImagesByIds($oOrderModel->annex ? explode(',', $oOrderModel->annex) : []),
        ];

        $formatData['delivery'] = [];
        $formatData['delivery'][] = [
            'name' => $oOrderModel->first_name . ' ' . $oOrderModel->last_name,
            'phone' => $oOrderModel->phone,
            'email' => $oOrderModel->email,
            'zip_code' => $oOrderModel->zip_code,
            'address' => $oOrderModel->address,
            'address2' => $oOrderModel->address2,
            'company' => $oOrderModel->company,
            'prescription' => $oOrderModel->prescription,
            'country_id' => $oOrderModel->country_id,
            'city_id' => $oOrderModel->city_id,
            'country_name' => $oOrderModel->country_name,
            'city_name' => $oOrderModel->city_name,
            'state_id' => $oOrderModel->state_id,
            'state' => $oOrderModel->state,
            'first_name' => $oOrderModel->first_name,
            'last_name' => $oOrderModel->last_name,
            'ship_date' => $oOrderModel->ship_date,
            'delivery_remark' => $oOrderModel->delivery_remark
        ];

        $formatData['logistics'] = [];

        // 查询所有物流订单项，并联接相关数据
        $logisticsItems = Db::name('logistics_order_item')
            ->alias('a')
            ->leftJoin('db_logistics_order b', 'a.logistics_order_id = b.id')
            ->where('a.order_id', $oOrderModel->id)
            ->where('b.type', 1)
            ->field('a.order_id,
                a.logistics_order_id,
                a.product_id,
                a.warehouse_id,
                a.number,
                a.create_time,
                b.company_id,
                b.logistics_no,
                b.logistics_voucher,
                b.cost,
                b.transaction_currency_id,
                b.notes,
                b.status,
                b.serial_number,
                b.ship_date')
            ->select()
            ->toArray();
        // 提前查询所有产品和仓库信息，存入数组
        $productIds = array_column($logisticsItems, 'product_id');
        $warehouseIds = array_column($logisticsItems, 'warehouse_id');

        $products = Db::name('product')
            ->whereIn('id', $productIds)
            ->field('id, code as product_code, cname as product_name')
            ->select()->toArray();
        $products = array_column($products, null, 'id');

        $warehouses = Db::name('warehouse')
            ->whereIn('id', $warehouseIds)
            ->field('id, name as warehouse_name')
            ->select()->toArray();
        $warehouses = array_column($warehouses, null, 'id');

        // 提前处理图片数据，避免每次循环都查询
        $oImages = new Images();

        // 用于存储合并后的物流数据
        $mergedLogistics = [];
        // 遍历物流订单项，合并数据
        foreach ($logisticsItems as $item) {
            $logisticsId = $item['logistics_order_id'];
            $product = $products[$item['product_id']] ?? [];
            $warehouse = $warehouses[$item['warehouse_id']] ?? [];
            // 物流项明细
            $logisticsItem = [
                'product_id' => $item['product_id'],
                'product_name' => $product['product_name'] ?? '',
                'product_code' => $product['product_code'] ?? '',
                'warehouse_name' => $warehouse['warehouse_name'] ?? '',
                'number' => $item['number'],
            ];
            if (isset($mergedLogistics[$logisticsId])) {
                $mergedLogistics[$logisticsId]['children'][] = $logisticsItem;
                continue;
            }
            // 处理物流凭证
            $voucherUrls = [];
            if (!empty($item['logistics_voucher'])) {
                $voucherIds = array_filter(array_unique(explode(',', $item['logistics_voucher'])));
                $voucherUrls = $oImages->getImagesByIds($voucherIds);
            }
            if (!empty($item['cost'])) {
                $item['cost'] = json_decode($item['cost']);
            }
            // 如果物流订单不存在，初始化数据
            $mergedLogistics[$logisticsId] = [
                'id' => $logisticsId,
                'company' => $item['company_id'],
                'logistics_no' => $item['logistics_no'],
                'cost' => $item['cost'],
                'transaction_currency_id' => $item['transaction_currency_id'],
                'notes' => $item['notes'],
                'create_time' => $item['create_time'],
                'logistics_voucher' => $voucherUrls,
                'status_value' => (new LogisticsOrderModel())->getAttributes('status')[$item['status']] ?? '',
                'status' => $item['status'],
                'ship_date' => $item['ship_date'],
                'serial_number' => $item['serial_number']
            ];
            $mergedLogistics[$logisticsId]['children'][] = $logisticsItem;
        }

        $formatData['logistics'] = array_values($mergedLogistics);
        // 最终的格式化数据
        $orderItemType = [];
        foreach ($formatData['list'] as $item) { // 前台是否显示库存类型转换
            if (0 != $item['is_futures'] && $item['quantity'] > 0) {
                $orderItemType[] = $item['is_futures'];
            }
        }
        $formatData['show_entry'] = (in_array(1, $orderItemType) || in_array(2, $orderItemType)) && $oOrderModel->pay_status == 3 && $oOrderModel->review_node == 0; // 是否显示库存类型转换

        // 计算订单可部分发货金额
        $partDeliveryRatio = SystemConfigModel::where(['key' => 'PART_DELIVERY_PRODUCT_AMOUNT_RATIO'])->value('value');
        $formatData['part_delivery_amount'] = $oOrderModel->pay_amount * (floatval($partDeliveryRatio ?: 0) / 100);

        $formatData['current_serial_number'] = $this->getCurrenSerialNumber($oOrderModel); // 当前发货单号

        return ['code' => 0, 'message' => 'success', 'data' => $formatData];
    }
    /**
     * @describe 获取当前发货单号
     * @author: Bobo
     * @date: 2025-08-18 16:13:30
     * @param [type] @required
     * @return Renderable
     */
    public function getCurrenSerialNumber($oOrderModel)
    {
        // 获取当前订单最新的序列号
        $lastSerialNumber = Db::name('logistics_order_item')
            ->alias('a')
            ->join('db_logistics_order b', 'a.logistics_order_id = b.id')
            ->where('order_id', $oOrderModel->id)
            ->field('b.serial_number')
            ->order('b.serial_number desc')
            ->value('b.serial_number');

        // 如果没有序列号，返回初始序列号
        if (!$lastSerialNumber) {
            return sprintf('%d-01', $oOrderModel->id);
        }

        // 提取并递增序号
        $sequence = (int)substr($lastSerialNumber, strpos($lastSerialNumber, '-') + 1);
        return sprintf('%d-%02d', $oOrderModel->id, $sequence + 1);
    }

    /**
     * 下拉框选择接口
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getSelect()
    {
        $where = [['is_del', '=', 0]];
        $arrData = ['code' => 0, 'message' => 'success'];

        $field = ['id', 'name'];
        $oOrderModel = OrderModel::where($where);
        $total = $oOrderModel->count();
        $result = $oOrderModel->field('id AS value,name as label')->select();
        $arrData['data'] = ['list' => $result->toArray(), 'total' => $total];
        return $arrData;
    }

    /**
     * 调仓 可用库存列表
     */
    public function getInventoryByAbbr($id)
    {
        $data = [];

        if (!$id) {
            return ['code' => 1, 'message' => 'id必填'];
        }
        $iterm = OrderItemModel::where('id', $id)->find()->toArray();

        if (empty($iterm)) {
            return ['code' => 1, 'message' => '订单数据不存在'];
        }
        if ($iterm['pending_quantity'] <= 0) {
            return ['code' => 1, 'message' => '已发货订单无需操作'];
        }
        $abbr = \app\admin\model\Product::where('id', $iterm['product_id'])->value('abbr');
        $product = \app\admin\model\Product::where('abbr', $abbr)->where('is_del', 0)->where('status', 1)->select()->toArray();
        if ($product) {
            $pids = array_column($product, 'id');
            $product = array_column($product, null, 'id');
            $inventory = \app\admin\model\Inventory::where(
                ['is_del' => 0, 'is_futures' => 0]
            )->whereIn('productid', $pids)
                ->whereRaw(" available_qty - lock_qty >= {$iterm['pending_quantity']}")
                ->select()->toArray();

            if (empty($inventory)) {
                return ['code' => 1, 'message' => '无可用库存'];
            }

            $wid = array_unique(array_column($inventory, 'wid'));
            $warehouse = \app\admin\model\Warehouse::whereIn('id', $wid)->select()->toArray();
            $warehouse = array_column($warehouse, null, 'id');
            foreach ($inventory as $k => $v) {
                $data[$k]['product_name'] = $product[$v['productid']]['cname'] ?? '';
                $data[$k]['product_abbr'] = $product[$v['productid']]['abbr'] ?? '';
                $data[$k]['warehouse_name'] = $warehouse[$v['wid']]['name'] ?? '';
                $data[$k]['available_qty'] = $v['available_qty'] - $v['lock_qty'];
                $data[$k]['lock_qty'] = $v['lock_qty'];
                $data[$k]['id'] = $v['id'];
            }
        }

        return ['code' => 0, 'message' => 'success', 'data' => $data];
    }

    /**
     * 调仓 可用库存列表
     */
    public function changeWarehouse($param)
    {
        $data = [];
        if (!isset($param['iterm_id']) || !isset($param['inventory_id']) || !$param['iterm_id'] || !$param['inventory_id']) {
            return ['code' => 1, 'message' => '参数错误'];
        }
        $iterm = OrderItemModel::where('id', $param['iterm_id'])->find()->toArray();
        $inventory = \app\admin\model\Inventory::where('id', $param['inventory_id'])->find()->toArray();
        if (empty($iterm)) {
            return ['code' => 1, 'message' => '订单数据不存在'];
        }
        if (empty($inventory)) {
            return ['code' => 1, 'message' => '库存数据不存在'];
        }
        Db::startTrans();
        try {
            #解锁库存
            $conditions = [[
                'product_id' => $iterm['product_id'],
                'arrival_date' => $iterm['arrival_date'],
                'is_futures' => $iterm['is_futures'],
                'wid' => $iterm['warehouse_id'],
                'order_id' => $iterm['order_id'],
                'operator_id' => $param['operator_id'],
                'quantity' => $iterm['pending_quantity'],
            ]];
            $unlock = (new \app\common\service\Inventory())->unlockInventory($conditions);
            if (!$unlock) {
                throw new \Exception('释放库存失败');
            }
            $data = $iterm;
            $data['product_id'] = $inventory['productid'];
            $data['warehouse_id'] = $inventory['wid'];
            $data['arrival_date'] = $inventory['arrival_date'];
            $data['real_arrival_date'] = $inventory['real_arrival_date'];
            $data['is_futures'] = $inventory['is_futures'];
            if ($iterm['pending_quantity'] != $iterm['quantity']) {
                $data['quantity'] = $iterm['pending_quantity'];
                $data['create_time'] = date('Y-m-d H:i:s');
                unset($data['id']);
                OrderItemModel::where('id', $iterm['id'])->update(['pending_quantity' => 0, 'quantity' => $iterm['pending_quantity']]);
                OrderItemModel::insert($data);
            } else {
                OrderItemModel::where('id', $iterm['id'])->update($data);
            }
            #锁定库存
            $update = \app\admin\model\Inventory::where('id', $param['inventory_id'])->inc('lock_qty', $iterm['pending_quantity'])->update();
            if ($update) {
                $insert_param = [
                    'inventory_id' => $param['inventory_id'],
                    'business_tabel_name' => 'order',
                    'business_table_id' => $iterm['order_id'],
                    'business' => '调仓-调入',
                    'remark' => '订单调仓，锁定库存',
                    'number' => $iterm['pending_quantity'],
                    'operator_id' => $param['operator_id'],
                ];
                (new \app\common\service\Inventory())->insertInventoryChanggeData($insert_param);
            }
            $cacheLogic = new CacheLogic();
            $cacheLogic->clearCache(6); // 清除C端产品缓存
            DB::commit();
        } catch (Exception $e) {
            DB::rollback();
            Log::info('调仓失败：' . $e->getMessage());
            return ['code' => 1, 'message' => '调仓失败'];
        }

        $this->logger->logOperation($iterm['order_id'], 'order', '订单-调仓', '订单商品调仓 item_id : '.$param['iterm_id'].' inventory_id : '.$param['inventory_id'],1,'inventory',$param['inventory_id']);
        return ['code' => 0, 'message' => 'success'];
    }

    /**
     * @param $param
     * @return array|void
     * @throws \app\api\exception\ParameterException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 2025-1-16 14 05
     * author: bobo
     */
    public function delivery($param)
    {
        Db::startTrans();
        try {
            $oOrderModel = OrderModel::with('items')->where([['id', '=', $param['order_id']], ['is_del', '=', 0]])->find();

            // 检查订单是否存在
            if (!$oOrderModel) {
                throw new Exception('订单不存在');
            }

            if ($oOrderModel->aftersales_status != null) {
                throw new Exception('订单售后状态不为空，无法发货');
            }
            // 如果是物流配送方式，检查物流公司是否存在
            if ($oOrderModel->delivery_method == 1) {
                $oLogisticsCompanyModel = LogisticsCompanyModel::where([['id', '=', $param['logistics_company']], ['is_del', '=', 0], ['status', '=', 1]])->find();
                if (!$oLogisticsCompanyModel) {
                    throw new Exception('物流公司不存在');
                }
            }

            // 将订单对象转为数组
            $oOrderModelArr = $oOrderModel->toArray();

            // 初始化变量
            $total_num = 0; // 前台提交需要发货数量合计
            $total_quantity = $oOrderModel->items()->sum('pending_quantity'); // 需要发货数量合计

            $product_list = [];
            // $total_logistics_fee = 0;

            // 遍历前台提交的发货列表
            foreach ($param['list'] as $item) {
                // 累计发货数量
                $total_num += $item['ship_quantity'];
                $product_list[] = [
                    'id' => $item['product_id'],
                    'number' => $item['ship_quantity']
                ];

                // 检查每个订单项的发货数量是否超过待发货数量
                foreach ($oOrderModelArr['items'] as $ery) {
                    if ($ery['id'] == $item['id'] && $ery['pending_quantity'] < $item['ship_quantity']) {
                        throw new Exception('发货数量不能大于订单数量');
                    }
                }
            }

            // 检查总发货数量是否超过总待发货数量
            if ($total_num > $total_quantity) {
                throw new Exception('发货数量不能大于订单数量');
            }

            // 判断是否全部发货
            // 创建一个发货单
            // 修改订单状态和发货数量

            // 更新父级订单明细待发货数量
            $oOrderModelArr = $oOrderModel->toArray();

            $productInventoryService = new ProductInventoryService();


            // 更新每个订单项的待发货数量
            foreach ($oOrderModelArr['items'] as $dep) {
                foreach ($param['list'] as $que) {

                    if ($dep['id'] == $que['id']) {
                        $condition = [[
                            'productid' => $que['product_id'],
                            'wid' => $que['wid'],
                            'arrival_date' => $que['arrival_date'],
                            'is_futures' => $que['is_futures'],
                            'quantity' => $que['ship_quantity']
                        ]];
                        $inventoryList = $productInventoryService->inventory($condition, 'delivery');

                        if ($inventoryList['code'] == 0 && count($inventoryList['data']) > 0) {
                            $inventoryList = $inventoryList['data'];
                        } else {
                            throw new Exception('可用库存不足');
                        }

                        $reduced_quantity = $que['ship_quantity']; // 需要扣减的库存数量


                        $inventoryList = array_column($inventoryList, null, 'productid');
                        $inventoryList = $inventoryList[$que['product_id']]['items'];


                        foreach ($inventoryList as $inventory) {

                            // 如果已完成全部扣减，跳出循环
                            if ($reduced_quantity <= 0) {
                                break;
                            }
                            if ($inventory['available_qty'] > 0) {
                                $inventoryInfo = Db::name('inventory')
                                    ->where('is_del', 0)
                                    ->where('id', $inventory['id'])
                                    ->field('id,available_qty,lock_qty')
                                    ->find();

                                if (!$inventoryInfo) {
                                    throw new Exception('库存记录不存在');
                                }

                                // 确定本次扣减数量
                                $deductQuantity = min($inventoryInfo['available_qty'], $reduced_quantity);

                                if ($deductQuantity > $inventoryInfo['available_qty']) {
                                    continue; // 跳过可用库存不足的记录
                                }
                                // 扣减库存
                                $resultUpdateQuery = Db::name('inventory')
                                    ->where([
                                        ['id', '=', $inventory['id']],
                                        ['available_qty', '>=', $deductQuantity]
                                    ])
                                    ->dec('available_qty', $deductQuantity);
                                if ($param['shop_fl_warehouse'] != 1) {  // 真实仓库发货 扣减锁定库存 虚拟仓库不扣减锁定库存
                                    $resultUpdateQuery->dec('lock_qty', $deductQuantity);
                                }
                                $resultUpdate = $resultUpdateQuery->update();

                                if (!$resultUpdate) {
                                    throw new Exception('库存扣减失败');
                                }
                                if ($oOrderModel->order_type === 2) {
                                    $business_table_id = $dep['wholesal_id'];
                                    $remark = '经销商发货，扣减库存 发货订单ID: ' . $param['order_id'];
                                } else {
                                    $business_table_id = $param['order_id'];
                                    $remark = '订单发货，扣减库存';
                                }
                                // 记录库存变动
                                $resultInsert = Db::name('inventory_change_record')->insert([
                                    'inventory_id' => $inventory['id'],
                                    'business_tabel_name' => 'order',
                                    'business_table_id' => $business_table_id,
                                    'business' => '订单发货',
                                    'number' => $deductQuantity,
                                    'remark' => $remark,
                                    'creator' => $param['operator_id'],
                                    'create_time' => date('Y-m-d H:i:s', time()),
                                ]);

                                if (!$resultInsert) {
                                    throw new Exception('库存变动记录创建失败');
                                }
                                // 更新剩余需要扣减的数量
                                $reduced_quantity -= $deductQuantity;
                            }
                        }

                        if ($reduced_quantity > 0) {
                            throw new Exception('可用库存不足');
                        }
                        // 更新盘点明细表
                        Db::name('product_sold_stat')->where([
                            'productid' => $que['product_id'],
                            'warehouse_id' => $que['wid'],
                        ])
                            ->dec('available_qty', $que['ship_quantity'])
                            ->dec('pending_qty', $que['ship_quantity'])
                            ->update([
                                'update_time' => date('Y-m-d H:i:s', time()),
                            ]);
                        // 计算新的待发货数量
                        $pending_quantity = $dep['pending_quantity'] - $que['ship_quantity'];
                        OrderItemModel::where('id', $dep['id'])->update(['pending_quantity' => $pending_quantity]);

                        // 如果是待支付且部分支付状态，更新部分发货申请的待发数量
                        if ($oOrderModel->status == 10 && $oOrderModel->pay_status == 4) {
                            // 获取所有相关的申请项
                            $applyItems = Db::name('order_part_delivery_apply_item')
                                ->alias('item')
                                ->join('order_part_delivery_apply apply', 'item.order_part_delivery_apply_id = apply.id')
                                ->where([
                                    ['item.order_item_id', '=', $dep['id']],
                                    ['apply.order_id', '=', $oOrderModel->id],
                                    ['item.is_del', '=', 0],
                                    ['apply.is_del', '=', 0],
                                    ['apply.status', '=', 2]
                                ])
                                ->order('item.id asc')
                                ->field(['pending_quantity', 'item.id as item_id'])
                                ->select()
                                ->toArray();

                            if ($applyItems) {
                                $remainQuantity = $que['ship_quantity']; // 剩余需要减少的数量
                                foreach ($applyItems as $applyItem) {
                                    if ($remainQuantity <= 0) {
                                        break;
                                    }

                                    // 当前申请项可以减少的数量
                                    $reduceQuantity = min($remainQuantity, $applyItem['pending_quantity']);
                                    if ($reduceQuantity > 0) {
                                        // 更新当前申请项的待发数量
                                        Db::name('order_part_delivery_apply_item')
                                            ->where('id', $applyItem['item_id'])
                                            ->update([
                                                'pending_quantity' => Db::raw('pending_quantity - ' . $reduceQuantity)
                                            ]);

                                        $remainQuantity -= $reduceQuantity;
                                    }
                                }
                            }
                        }
                        #最后发货时间
                        $update_logic  = Db::name('logistics_order')->alias('lo')->join('logistics_order_item loi ', 'loi.logistics_order_id = lo.id')
                            ->whereRaw("lo.type = 1 and lo.status = 1  and loi.order_id = {$param['order_id']}")
                            ->order('ship_date', 'desc')->find();
                        $ship_date = max($update_logic['ship_date'] ?? null, $param['ship_date']);

                        // 如果是经销商的发货订单则 还需要更新主经销商订单信息
                        // 获取主经销商订单信息
                        if ($oOrderModel->order_type === 2) {
                            $mainOrderModel = OrderModel::where('id', $dep['wholesal_id'])->with('itemList')->find();
                            $mainOrderModel->last_delivery_time = $ship_date;
                            $mainOrderModel->save();
                            // foreach ($mainOrderModel->itemList as $who) {
                            //     if ($who['quantity'] <= 0) { // 主经销商订单明细数量为0 则跳过
                            //         continue;
                            //     }
                            $whereItem = [
                                ['product_id', '=', $dep['product_id']],
                                ['is_futures', '=', $dep['is_futures']],
                                ['warehouse_id', '=', $dep['warehouse_id']],
                                ['arrival_date', '=', $dep['arrival_date']],
                                ['order_id', '=', $dep['wholesal_id']],
                                ['is_del', '=', 0],
                                ['lock_qty', '>', 0],
                                ['quantity', '>', 0],
                                ['pending_quantity', '>', 0]
                            ];
                            $oWholesalOrderItemModel = OrderItemModel::where($whereItem)->select();

                            $surplus = $que['ship_quantity']; // 剩余发货数量

                            foreach ($oWholesalOrderItemModel as $item) {
                                // 更新发货数量
                                if ($item['lock_qty'] >= $surplus) {
                                    $update = [
                                        'lock_qty' => $item['lock_qty'] - $surplus,
                                        'pending_quantity' => $item['pending_quantity'] - $surplus,
                                    ];
                                    if (!OrderItemModel::where('id', $item['id'])->update($update)) {
                                        throw new Exception("订单明细更新失败！");
                                    }
                                    break;
                                } else {
                                    $update = [
                                        'lock_qty' => 0,
                                        'pending_quantity' => $item['pending_quantity'] - $item['lock_qty'],
                                    ];
                                    $surplus = $surplus - $item['lock_qty'];
                                }
                                if (!OrderItemModel::where('id', $item['id'])->update($update)) {
                                    throw new Exception("订单明细更新失败！");
                                }
                            }
                            // }
                        }

                        /* 虚拟仓库下单减锁定数量 */
                        if ($param['shop_fl_warehouse'] == 1) {

                            $condition = [];
                            $mergedItems = [];

                            foreach ($param['list'] as $item) {
                                $key = implode('_', [
                                    $param['order_id'],
                                    $item['product_id'],
                                    $item['fl_warehouse_id'],
                                    $item['arrival_date'],
                                    $item['is_futures']
                                ]);

                                if (!isset($mergedItems[$key])) {
                                    $mergedItems[$key] = [
                                        'order_id' => $param['order_id'],
                                        'product_id' => $item['product_id'],
                                        'wid' => $item['fl_warehouse_id'],
                                        'arrival_date' => $item['arrival_date'],
                                        'is_futures' => $item['is_futures'],
                                        'operator_id' => $param['operator_id'],
                                        'quantity' => $item['ship_quantity']
                                    ];
                                } else {
                                    $mergedItems[$key]['quantity'] += $item['ship_quantity'];
                                }
                            }

                            $condition = array_values($mergedItems);
                            // 释放锁定库存
                            $inventory = new CommonInventoryService();
                            $lockResult = $inventory->unlockInventory($condition);
                            if (!$lockResult) {
                                throw new \Exception('库存释放失败，请确认库存情况');
                            }
                        }
                    }
                }
            }

            // 如果是物流配送方式，创建物流单
            if ($oOrderModel->delivery_method == 1 || $oOrderModel->delivery_method == 0 || $oOrderModel->delivery_method == 2) {
                // 创建物流单
                $address = $param['shippinAddress'];

                $oLogisticsModel = new LogisticsOrderModel();
                $oLogisticsModel->company_id = $param['logistics_company'];
                $oLogisticsModel->logistics_no = $param['logistics_no'];
                $oLogisticsModel->logistics_voucher = implode(',', $param['logistics_voucher']);
                $oLogisticsModel->notes = $param['notes'];
                $oLogisticsModel->transaction_currency_id = $param['transaction_currency_id'];
                $oLogisticsModel->cost = json_encode($param['cost']);
                $oLogisticsModel->create_time = date('Y-m-d H:i:s');

                $oLogisticsModel->first_name = $address['first_name'] ?? '';
                $oLogisticsModel->last_name = $address['last_name'] ?? '';
                $oLogisticsModel->email = $address['email'] ?? '';
                $oLogisticsModel->phone = $address['phone'] ?? '';
                $oLogisticsModel->address = $address['address'] ?? '';
                $oLogisticsModel->country_id = $address['country_id'] ?? '';
                $oLogisticsModel->country_name = $address['country_name'] ?? '';

                $oLogisticsModel->city_id = $address['city_id'] ?? '';
                $oLogisticsModel->city_name = $address['city_name'] ?? '';
                $oLogisticsModel->zip_code = $address['zip_code'] ?? '';
                $oLogisticsModel->state_id = $address['state_id'] ?? '';
                $oLogisticsModel->state = $address['state'] ?? '';
                $oLogisticsModel->company = $address['company'] ?? '';
                $oLogisticsModel->address2 = $address['address2'] ?? '';
                $oLogisticsModel->ship_date = $param['ship_date'] ?? '';
                $oLogisticsModel->serial_number = $this->getSerialNumber($oOrderModelArr);

                $oLogisticsModel->save();

                // 检查物流单是否创建成功
                if (!$oLogisticsModel->save()) {
                    throw new Exception('物流单创建失败');
                } else {
                    // 创建物流单明细
                    $logisticsOrderItemArr = [];
                    foreach ($param['list'] as $paramItem) {
                        $logisticsOrderItemArr[] = [
                            'logistics_order_id' => $oLogisticsModel->id,
                            'order_id' => $oOrderModel->id,
                            'product_id' => $paramItem['product_id'],
                            'warehouse_id' => $paramItem['wid'],
                            'number' => $paramItem['ship_quantity'],
                            'create_time' => date('Y-m-d H:i:s'),
                        ];
                    }
                    // 批量插入物流单明细
                    if (!DB::name('logistics_order_item')->insertAll($logisticsOrderItemArr)) {
                        throw new Exception('物流单明细创建失败');
                    }
                }
            }

            // 计算订单剩余待发货数量
            $totalPendingQuantity = Db::name('order_item')->where('is_del', 0)->where('order_id', $oOrderModel->id)->sum('pending_quantity');

            $event = '';
            $oOrderModel->last_delivery_time = $ship_date;
            if (!$param['is_part_delivery']) {
                // 根据是否还有待发货数量更新订单状态
                if ($totalPendingQuantity > 0) {
                    // 部分发货，状态为40
                    $oOrderModel->status = 40;
                    $oOrderModel->shipping_time = date('Y-m-d H:i:s');
                    if (!$oOrderModel->save()) {
                        throw new Exception('订单状态修改失败');
                    }
                    $event = 'order_partial_delivered';
                } else {
                    // 全部发货，状态为50
                    $oOrderModel->status = 50;
                    $oOrderModel->shipping_time = date('Y-m-d H:i:s');
                    if (!$oOrderModel->save()) {
                        throw new Exception('订单状态修改失败');
                    }
                    $event = 'order_delivered';
                }
            }

            $this->logger->logOperation($oOrderModel->id, 'order', '订单-发货', '订单发货',1,'logistics_order',$oLogisticsModel->id);


            DB::commit();
            if ($oLogisticsModel->logistics_no) {
                $mailService = new Mail();
                $mailService->send('order_shipped', [
                    'logistics' => $oLogisticsModel->toArray(),
                    'order_info' => $oOrderModel->toArray()
                ]);
            }
            if ($event) {
                $orderInfo = $oOrderModel->toArray();
                $orderInfo['logistics_no'] = '';
                if ($oOrderModel->delivery_method == 1 || $oOrderModel->delivery_method == 0 || $oOrderModel->delivery_method == 2) {
                    $orderInfo['logistics_no'] = $oLogisticsModel->logistics_no;
                }
                $partnerArr = $oOrderModel->partner ? array_filter(explode(',', $oOrderModel->partner)) : [];
                $notificationService = new CompleteNotificationService();
                $notificationService->send($event, $orderInfo, [$oOrderModel->owner, $oOrderModel->signatory, ...$partnerArr]);
            }
        } catch (Exception $e) {
            DB::rollback();
            return ['code' => 1, 'message' => $e->getMessage()];
        }
        #shopify 订单 发货通知
        try {
            if ($oOrderModel['source'] == 2) {
                $param['logistics_order'] =  $oLogisticsModel->id;
                $shopify = new FulfillmentService();
                $shopify->createOrUpdateFulfillment($param);
            }
        } catch (Exception $e) {
            Log::error('通知shopify发货失败 ：' . $e->getMessage());
        }

        return ['code' => 0, 'message' => '发货成功'];
    }
    #生产发货单号  订单号-第几次发货
    private function getSerialNumber($order)
    {
        $count = Db::name('logistics_order')->alias('lo')->join('logistics_order_item loi ', 'loi.logistics_order_id = lo.id')
            ->whereRaw("loi.order_id = {$order['id']}")->group('order_id ,logistics_order_id')
            ->count();
        ++$count;
        $serial = str_pad($count, 2, '0', STR_PAD_LEFT);
        $number = $order['id'] . '-' . $serial;
        return $number;
    }
    #取消发货
    public function cancelDelivery($param)
    {
        $shipInfo = LogisticsOrderModel::with('items')->where([['id', '=', $param['id']], ['status', '=', 1]])->find();
        if (empty($shipInfo)) {
            return ['code' => 1, 'message' => '找不到发货单信息 '];
        }
        $shipInfo = $shipInfo->toArray();
        Db::startTrans();
        try {
            foreach ($shipInfo['items'] as $item) {
                $inventory = InventoryModel::where([
                    'productid' => $item['product_id'],
                    'wid' => $item['warehouse_id'],
                    'is_futures' => 0,
                    'is_del' => 0,
                ])->find()->toArray();
                if (empty($inventory)) {
                    throw new Exception('找不到库存');
                }
                $resultUpdate = Db::name('inventory')
                    ->where([
                        'productid' => $item['product_id'],
                        'wid' => $item['warehouse_id'],
                        'is_futures' => 0,
                        'is_sale' => 1,
                        'is_del' => 0,
                    ])->order('create_time desc')
                    ->limit(1)
                    ->inc('lock_qty', $item['number'])
                    ->inc('available_qty', $item['number'])
                    ->update();
                // 记录库存变动
                $resultInsert = Db::name('inventory_change_record')->insert([
                    'inventory_id' => $inventory['id'],
                    'business_tabel_name' => 'logistics_order',
                    'business_table_id' => $shipInfo['id'],
                    'business' => '订单发货',
                    'number' => $item['number'],
                    'remark' => '发货撤销，库存回退',
                    'creator' => $param['operator_id'],
                    'create_time' => date('Y-m-d H:i:s', time()),
                ]);
                $oOrderModel = OrderModel::where([['id', '=', $item['order_id']], ['is_del', '=', 0]])->find();
                #取消发货
                $update_logic  = Db::name('logistics_order')->alias('lo')->join('logistics_order_item loi ', 'loi.logistics_order_id = lo.id')
                    ->whereRaw("lo.type = 1 and lo.status = 1 and loi.logistics_order_id != {$shipInfo['id']} and loi.order_id = {$item['order_id']}")
                    ->order('ship_date', 'desc')->find();

                $oOrderModel->last_delivery_time = $update_logic['ship_date'] ?? null;

                $oOrderModel->save();
                #经销商发货订单 撤销 增加原资产订单 lock 和 pending
                if ($oOrderModel->order_type == 2) {
                    $wholesal_id = OrderItemModel::where('order_id', $item['order_id'])
                        ->where('product_id', $item['product_id'])
                        ->where('warehouse_id', $item['warehouse_id'])
                        ->where('is_futures', 0)->value('wholesal_id');
                    if (!$wholesal_id) {
                        Log::error('提篮子现货发货，仓库变了找不到原资产订单，无法取消');
                        throw new Exception('虚拟仓发货，找不到原资产订单');
                    }

                    $items =  OrderItemModel::where('order_id', $wholesal_id)
                        ->where('product_id', $item['product_id'])
                        ->where('warehouse_id', $item['warehouse_id'])
                        ->where('is_futures', 0)->select()->toArray();

                    $pending_return = $item['number'];
                    foreach ($items as $zc_item) {
                        $min_a_quantity = min($zc_item['quantity'] - $zc_item['pending_quantity'], $zc_item['quantity'] - $zc_item['lock_qty']);
                        if ($pending_return <= $min_a_quantity) {
                            OrderItemModel::where('id', $zc_item['id'])
                                ->inc('lock_qty', $pending_return)
                                ->inc('pending_quantity', $pending_return)
                                ->update();
                            $pending_return = 0;
                        } else {
                            OrderItemModel::where('id', $zc_item['id'])
                                ->inc('lock_qty', $min_a_quantity)
                                ->inc('pending_quantity', $min_a_quantity)
                                ->update();
                            $pending_return = $pending_return - $min_a_quantity;
                        }
                    }
                    if ($pending_return > 0) {
                        throw new Exception('发货订单的原资产订单数据异常');
                    }
                }
                $count = Db::name('logistics_order')->alias('lo')->join('logistics_order_item loi ', 'loi.logistics_order_id = lo.id')
                    ->whereRaw("lo.type = 1 and lo.status = 1 and loi.logistics_order_id != {$shipInfo['id']} and order_id = {$item['order_id']}")
                    ->count();

                $orderStatus = $count > 0 ? 40 : 30;
                #更新订单状态
                OrderModel::where([['id', '=', $item['order_id']], ['is_del', '=', 0]])->update(['status' => $orderStatus]);

                #更新明细待发货数量
                $ir = OrderItemModel::where('order_id', $item['order_id'])
                    ->where('product_id', $item['product_id'])
                    ->where('warehouse_id', $item['warehouse_id'])
                    ->where('is_futures', 0)
                    ->inc('lock_qty', $item['number'])
                    ->inc('pending_quantity', $item['number'])
                    ->update();

                // 如果是待支付且部分支付状态，更新部分发货申请的待发数量
                if ($oOrderModel->status == 10 && $oOrderModel->pay_status == 4) {
                    // 获取所有相关的申请项
                    $applyItems = Db::name('order_part_delivery_apply_item')
                        ->alias('item')
                        ->join('order_part_delivery_apply apply', 'item.order_part_delivery_apply_id = apply.id')
                        ->where([
                            ['item.order_item_id', '=', $item['order_item_id']],
                            ['apply.order_id', '=', $oOrderModel->id],
                            ['item.is_del', '=', 0],
                            ['apply.is_del', '=', 0],
                            ['apply.status', '=', 2]
                        ])
                        ->order('item.id asc')
                        ->select()
                        ->toArray();

                    if ($applyItems) {
                        $remainQuantity = $item['number']; // 剩余需要增加的数量
                        foreach ($applyItems as $applyItem) {
                            if ($remainQuantity <= 0) {
                                break;
                            }

                            // 更新当前申请项的待发数量
                            Db::name('order_part_delivery_apply_item')
                                ->where('id', $applyItem['id'])
                                ->update([
                                    'pending_quantity' => Db::raw('pending_quantity + ' . $remainQuantity)
                                ]);

                            $remainQuantity = 0; // 全部加回到第一个申请项
                        }
                    }
                }

                // 更新盘点明细表
                Db::name('product_sold_stat')->where([
                    'productid' => $item['product_id'],
                    'warehouse_id' => $item['warehouse_id'],
                ])
                    ->inc('available_qty', $item['number'])
                    ->inc('pending_qty', $item['number'])
                    ->update([
                        'update_time' => date('Y-m-d H:i:s', time()),
                    ]);

                if (30 == $oOrderModel->status) { // 待发货状态 发送通知
                    $notificationService = new CompleteNotificationService();
                    $notificationService->send('order_delivery_pending', $oOrderModel->toArray(), [], '', '50,51');
                }
                #更新发货单状态
                LogisticsOrderModel::where([['id', '=', $param['id']], ['status', '=', 1]])->update(['status' => 2]);
            }
            $this->logger->logOperation($oOrderModel->id, 'order', '订单-取消发货', '订单发货撤销',1,'logistics_order',$param['id']);
            DB::commit();
        } catch (Exception $e) {
            DB::rollback();
            return ['code' => 1, 'message' => $e->getMessage()];
        }
        return ['code' => 0, 'message' => '取消发货成功'];
    }
    /**
     * @param $param
     * @return array|void
     * @throws \app\api\exception\ParameterException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 2024-11-21 17 14 05
     * author: jiang
     */
    public function deliveryOld($param)
    {
        Db::startTrans();
        try {
            $oOrderModel = OrderModel::with('items')->where([['id', '=', $param['order_id']], ['is_del', '=', 0], ['status', 'in', [30, 40]]])->find();
            if (!$oOrderModel) {
                throw new Exception('订单不存在');
            }
            if ($oOrderModel->delivery_method == 1) {
                $oLogisticsCompanyModel = LogisticsCompanyModel::where([['id', '=', $param['logistics_company']], ['is_del', '=', 0], ['status', '=', 1]])->find();
                if (!$oLogisticsCompanyModel) {
                    throw new Exception('物流公司不存在');
                }
            }

            $oOrderModelArr = $oOrderModel->toArray();
            if (!$oOrderModel) {
                throw new Exception('订单不存在');
            }
            $total_num = 0; //前台提交需要发货数量合计
            $total_quantity = $oOrderModel->items()->sum('pending_quantity'); // 需要发货数量合计
            $product_list = [];
            $total_logistics_fee = 0;
            foreach ($param['list'] as $item) {
                $total_num += $item['ship_quantity'];
                $product_list[] = [
                    'id' => $item['product_id'],
                    'number' => $item['ship_quantity']
                ];
                foreach ($oOrderModelArr['items'] as $ery) {
                    if ($ery['id'] == $item['id'] && $ery['pending_quantity'] < $item['ship_quantity']) {
                        throw new Exception('发货数量不能大于订单数量');
                    }
                }
            }
            if ($total_num > $total_quantity) {
                throw new Exception('发货数量不能大于订单数量');
            }
            // 判断是否全部发货
            $oDeliveryItem = OrderModel::with('items')->where([['is_del', '=', 0], ['pid', '=', $oOrderModel->id]])->select();
            if (count($oDeliveryItem) == 0) {
                // 无子订单
                $whole_delivery = $total_num == $total_quantity;
            } else {
                //有发货子订单
                $item_total_num = 0; // 子订单发货数量合计
                //                foreach ($oDeliveryItem as $jer) {
                //                    $total_logistics_fee += $jer->logistics_fee;
                //                    $item_total_num += $jer->items()->sum('pending_quantity');
                //                }
                $whole_delivery = $oOrderModel->items()->sum('pending_quantity') == $total_num;
            }

            if ($whole_delivery && count($oDeliveryItem) == 0) {
                // 全部发货(不创建子订单)
                $oOrderModel->status = 50;
                $oOrderModel->shipping_time = date('Y-m-d H:i:s');
                if (!$oOrderModel->save()) {
                    throw new Exception('订单状态修改失败');
                }
            } else {
                // 全部发货(创建子订单)
                $deliveryOrderModel = new OrderModel();
                // 运费
                $from_param = [
                    'shipping_warehouse' => $param['wid'],
                    'terms' => $oOrderModel->delivery_terms,
                    'to_nation' => $oOrderModel->country_id,
                    'prescription' => $oOrderModel->prescription,
                    'product_list' => $product_list
                ];
                $ServiceLogisticsRules = new AdminServiceLogisticsRules();
                $LogisticsFee = $ServiceLogisticsRules->getLogisticsFee($from_param);
                if ($LogisticsFee['code'] != 0) {
                    throw new Exception('获取运费失败');
                }
                $logistics_fee = $LogisticsFee['data']['fee'];
                //                $logistics_fee = 100;
                $logistics_fee_sum = $logistics_fee + $total_logistics_fee; // 当前发货运费 + 之前子订单运费
                $is_surplus = ($oOrderModel->pay_amount - $total_logistics_fee) > 0; //是否剩余
                //应付金额
                $account_payable = $is_surplus ? $logistics_fee_sum - $oOrderModel->pay_amount : $total_logistics_fee;

                $deliveryOrderModel->total_amount = $account_payable; //需要付款金额
                $deliveryOrderModel->pay_amount = 0;
                $deliveryOrderModel->logistics_fee = $logistics_fee;
                $deliveryOrderModel->pid = $oOrderModel->id;

                if (!$deliveryOrderModel->save()) {
                    throw new Exception('订单创建失败');
                }
                // 创建子订单
                $deliveryItem_insert = [];
                foreach ($param['list'] as $qwe) {
                    $deliveryItem_insert[] = [
                        'user_id' => $oOrderModel->user_id,
                        'order_id' => $deliveryOrderModel->id,
                        'product_id' => $qwe['product_id'],
                        'warehouse_id' => $qwe['wid'],
                        'original_price' => $qwe['original_price'],
                        'actual_price' => $qwe['actual_price'],
                        'creator' => $param['operator_id'],
                        'create_time' => date('Y-m-d H:i:s'),
                        'arrival_date' => $qwe['arrival_date'],
                        'is_futures' => $qwe['is_futures'],
                        'quantity' => $qwe['ship_quantity'],
                    ];
                }
                if (!OrderItemModel::insertAll($deliveryItem_insert)) {
                    throw new Exception('订单明细创建失败');
                }
            }
            // 更新父级订单明细待发货数量
            $oOrderModelArr = $oOrderModel->toArray();
            foreach ($oOrderModelArr['items'] as $dep) {
                foreach ($param['list'] as $que) {
                    if ($dep['id'] == $que['id']) {
                        $pending_quantity = $dep['pending_quantity'] - $que['ship_quantity'];
                        OrderItemModel::where('id', $dep['id'])->update(['pending_quantity' => $pending_quantity]);
                    }
                }
            }
            if ($oOrderModel->delivery_method == 1) {
                // 创建物流单
                $oLogisticsModel = new LogisticsOrderModel();
                $oLogisticsModel->order_id = $oOrderModel->id;
                $oLogisticsModel->company_id = $param['logistics_company'];
                $oLogisticsModel->logistics_no = $param['logistics_no'];
                $oLogisticsModel->logistics_voucher = implode(',', $param['logistics_voucher']);
                $oLogisticsModel->notes = $param['notes'];
                $oLogisticsModel->cost = $param['cost'];
                $oLogisticsModel->create_time = date('Y-m-d H:i:s');
                if (!$oLogisticsModel->save()) {
                    throw new Exception('物流单创建失败');
                }
            }
            if ($whole_delivery && count($oDeliveryItem) > 0) {
                $oOrderModel->status = 50;
                $oOrderModel->shipping_time = date('Y-m-d H:i:s');
                if (!$oOrderModel->save()) {
                    throw new Exception('订单状态修改失败');
                }
            }
            if (!$whole_delivery) {
                $oOrderModel->status = 40;
                $oOrderModel->shipping_time = date('Y-m-d H:i:s');
                if (!$oOrderModel->save()) {
                    throw new Exception('订单状态修改失败');
                }
            }
            $this->logger->logOperation($oOrderModel->id, 'order', 'delivery', '订单发货');
            DB::commit();
        } catch (Exception $e) {
            return ['code' => 1, 'message' => $e->getMessage()];
        }
        return ['code' => 0, 'message' => '发货成功'];
    }

    /**
     * 订单确认收货
     * @param $param
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 2024-11-22 16 21 55
     * author: jiang
     */
    public function receipt($param)
    {
        $oOrderModel = OrderModel::with('items')->where([['id', '=', $param['order_id']], ['status', '=', 50]])->find();
        if (!$oOrderModel) {
            return ['code' => 1, 'message' => '订单不存在或状态不正确'];
        }
        $oOrderModel->voucher = implode(',', $param['voucher']);
        $oOrderModel->status = 100; // 已完成
        if (!$oOrderModel->save()) {
            return ['code' => 1, 'message' => '订单确认收货失败'];
        }
        $this->logger->logOperation($oOrderModel->id, 'order', '确认收货', '订单确认收货');
        return ['code' => 0, 'message' => '订单确认收货成功'];
    }

    /**
     * 获取库存的枚举
     * @param $param
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 2024-12-18 16 13 09
     * author: jiang
     */
    public function transEnum($param)
    {
        $oOrderItemModel = OrderItemModel::find($param['id']);
        if (!$oOrderItemModel) {
            return ['code' => 1, 'message' => '未找到订单信息！'];
        }
        $futures = InventoryModel::getStaticEnum()['is_futures'];
        $data = [];
        foreach ($futures as $key => $value) {
            if ($oOrderItemModel->is_futures > $key) {
                $data[] = [
                    'label' => $value,
                    'value' => $key
                ];
            }
        }

        return ['code' => 0, 'message' => 'success', 'data' => $data];
    }

    /**
     * 获取库存 订单内库存类型转换，获取相关库存
     * @param $param
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 2024-12-18 16 41 33
     * author: jiang
     */
    public function getInventory($param)
    {
        $orderLogic = new OrderLogic();
        return $orderLogic->getInventory($param);
    }

    public function getFieldEnum($field)
    {
        $model = new OrderModel();
        $res = $model->getFieldEnum($field);
        return [
            'code' => 0,
            'data' => $res
        ];
    }

    /**
     * 确认付款
     * @param $param
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 2024-12-30 18 44 24
     * author: jiang
     */
    public function confirm($param)
    {
        $oOrderModel = OrderModel::where(['logistics_fee' => 0.0, 'status' => 10])->find($param['id']);
        if (!$oOrderModel) {
            return ['code' => 1, 'message' => '订单不存在或状态不正确'];
        }
        $oOrderModel->pay_status = 3;
        $oOrderModel->status = 30;

        if (!$oOrderModel->save()) {
            return ['code' => 1, 'message' => '订单确认付款失败'];
        }

        // 待发货状态 发送通知
        $notificationService = new CompleteNotificationService();
        $notificationService->send('order_delivery_pending', $oOrderModel->toArray(), [], '', '50,51');

        if (2 != $oOrderModel->order_type) { // 非经销商发货订单，需要锁定库存
            $res = (new \app\common\service\Inventory())->lockInventory(['id' => $oOrderModel->id, 'operator_id' => $param['operator_id']]);
            if (!$res) {
                Log::error("   库存锁定失败" . json_encode(['orderId' => $oOrderModel->id]));
                (new \app\common\service\Inventory())->updateOrderAfterLockInventoryFail($oOrderModel->id);
            }
        }
        $this->logger->logOperation($oOrderModel->id, 'order', '确认付款', '普通订单确认付款');
        return ['code' => 0, 'message' => '订单确认付款成功'];
    }



    /**
     *  选择商品非虚拟仓库
     */
    public function selectWarehouseProducts($param)
    {
        $orderItem = OrderItem::with(['warehouses' => function ($query) {
            $query->field('id,name,fl_warehouse_id,show_name');
        }])->where('id', '=', $param['id'])->find();

        if (!$orderItem) {
            return ['code' => 1, 'message' => '订单明细ID不存在'];
        }

        if (isset($orderItem->warehouses)) {
            if ($orderItem->warehouses->fl_warehouse_id != null) {
                return ['code' => 1, 'message' => '商品无法选择'];
            }
        }

        /* 查询子仓库 */
        $warehouse = WarehouseModel::where('fl_warehouse_id', '=', $orderItem->warehouse_id)
            ->where('is_del', '=', '0')
            ->where('status', '=', '1')
            ->field('id')->select();

        if (!$warehouse) {
            return ['code' => 1, 'message' => '无子子仓库'];
        }

        $warehouse = $warehouse->toArray();

        $wids = [];
        foreach ($warehouse as $value) {
            $wids[] = $value['id'];
        }


        /* 查询选可库存 */
        $where = [];
        $where[] = ['available_qty', '>', 0];
        $where[] = ['is_sale', '=', 1];
        $where[] = ['is_del', '=', 0];
        $where[] = ['productid', '=', $orderItem->product_id];
        $where[] = ['is_futures', '=', 0];
        $where[] = ['wid', 'in', $wids];

        $inventoryGroup = InventoryModel::with([
            'getProduct' => function ($query) {
                $query->with([
                    'getBrand' => function ($query) {
                        $query->field('id,name');
                    }
                ])->field('id,cname as name,hashrate,computing_unit,power,weight,model_id,code,brand,expiration_date,sales_price');
            },
            'warehouse' => function ($query) {
                $query->field('id,name,fl_warehouse_id');
            },
        ])->where($where);

        $inventoryGroup->field('id,wid,productid,available_qty,lock_qty,arrival_date,is_futures');
        $inventory = $inventoryGroup->select();

        if (! $inventory) {
            return ['code' => 1, 'message' => '未找到可用商品'];
        }

        $data = [];
        $i = 0;
        foreach ($inventory as $key => $item) {

            /* 小于零跳过 */
            if (($item->available_qty - $item->lock_qty) <= 0) {
                continue;
            }

            $data[$i]['fl_warehouse_id'] = null;
            if (isset($item->warehouse)) {
                $data[$i]['fl_warehouse_id'] = $item->warehouse->fl_warehouse_id;
            }

            $data[$i]['id'] = $orderItem->id;
            $data[$i]['quantity'] = $item->available_qty - $item->lock_qty;
            $data[$i]['arrival_date'] = $item->arrival_date;
            $data[$i]['is_futures'] = $item->is_futures;

            if (isset($item->warehouse)) {
                $data[$i]['wid'] = (int)$item->wid;
                $data[$i]['warehouse_name'] = $item->warehouse->name;
            }

            if (isset($item->getProduct)) {
                $data[$i]['product_id'] = $item->getProduct->id;
                $data[$i]['name'] = $item->getProduct->name;
                $data[$i]['hashrate'] = $item->getProduct->hashrate . $item->getProduct->computing_unit;
                $data[$i]['power'] = $item->getProduct->power;
                $data[$i]['code'] = $item->getProduct->code;
                $data[$i]['expiration_date'] = $item->getProduct->expiration_date;
                $data[$i]['original_price'] = $orderItem->original_price;
                $data[$i]['actual_price'] = $orderItem->actual_price;
                $data[$i]['actual_quoted_currency'] = null;
                $data[$i]['actual_selling_price'] = null;
                $data[$i]['actual_quoted_currency_name'] = null;

                if (isset($item->getProduct->getBrand)) {
                    $data[$i]['brand'] = $item->getProduct->getBrand->name;
                }
            }
            $i++;
        }

        return ['code' => 0, 'message' => 'success', 'data' => $data];
    }

    /**
     * @describe
     * @author: Bobo
     * @date: 2025-03-04 19:20:56
     * @param [type] @required
     * @return Renderable
     */
    public function getApprovalRecords(int $page = 1, int $limit = 10,  string $orderType = '', $orderId = 0, $field = "*")
    {
        $businessLogModel = new BusinessLog();
        $query = $businessLogModel
            ->with(['operator' => function ($query) {
                $query->bind(['user_name' => 'cname'])
                    ->field(['id', 'cname as user_name']);
            }])
            ->whereLike('business_module', '%' . $orderType . '%')
            ->whereLike('operate', '%审核%');

        // 通过orderId关联查询order_payment表
        if (!empty($orderId)) {
            $paymentIds = \app\admin\model\OrderPayment::where('order_id', $orderId)->column('id');
            if (!empty($paymentIds)) {
                array_push($paymentIds, $orderId);
                $query->whereIn('entity_id', $paymentIds);
            } else {
                $query->where('entity_id', $orderId);
            }
        }
        // 新增结束

        $total = $query->count();
        $list = $query
            ->field($field)
            ->page($page, $limit)
            ->order('id desc')
            ->select()
            ->each(function ($item) {
                if (isset($item['operator']['user_name'])) {
                    $item['user_name'] = $item['operator']['user_name'];
                    unset($item['operator']);
                } elseif ($item['user_type'] == 2) {
                    $item['user_name'] = '客户自己';
                }
                return $item;
            })
            ->toArray();

        return ['code' => 0, 'message' => 'success', 'data' => ['list' => $list, 'total' => $total]];
    }

    /**
     * 获取操作记录
     * @describe
     * @author: Assistant
     * @date: 2025-01-27 10:00:00
     * @param int $page 页码
     * @param int $limit 每页数量
     * @param string $orderType 订单类型
     * @param int $orderId 订单ID
     * @param string $field 查询字段
     * @return array
     */
    public function getOperationRecords(int $page = 1, int $limit = 10, string $orderType = '', $orderId = 0, $field = "*")
    {
        $businessLogModel = new BusinessLog();
        $query = $businessLogModel
            ->with(['operator' => function ($query) {
                $query->bind(['user_name' => 'cname'])
                    ->field(['id', 'cname as user_name']);
            }]);

        // 组合查询：订单操作记录 + 支付相关操作记录 + 物流相关操作记录
        $paymentIds = [];
        $logisticsIds = [];
        if (!empty($orderId)) {
            $paymentIds = \app\admin\model\OrderPayment::where('order_id', $orderId)->column('id');
            // 通过 orderId 关联查询物流单（仅 type = 1 的订单发货单）
            $logisticsIds = \think\facade\Db::name('logistics_order')->alias('lo')
                ->join('logistics_order_item loi', 'loi.logistics_order_id = lo.id')
                ->where('lo.type', 1)
                ->where('loi.order_id', $orderId)
                ->column('lo.id');
        }

        $query->where(function ($q) use ($orderId, $paymentIds, $logisticsIds) {
            // 订单本身的操作记录
            $q->where(function ($q1) use ($orderId) {
                $q1->where('business_module', 'order')
                    ->where('entity_id', $orderId);
            });

            // 支付相关的操作记录（business_module = orderPayment，entity_id in 支付记录ID）
            if (!empty($paymentIds)) {
                $q->whereOr(function ($q2) use ($paymentIds) {
                    $q2->where('business_module', 'orderPayment')
                        ->whereIn('entity_id', $paymentIds);
                });
            }
            // 物流相关的操作记录（business_module = logisticsOrder，entity_id in 物流记录ID 且 lo.type = 1）
            if (!empty($logisticsIds)) {
                $q->whereOr(function ($q3) use ($logisticsIds) {
                    $q3->where('business_module', 'order')
                        ->whereIn('entity_id', $logisticsIds);
                });
            }
        });

        $total = $query->count();
        $list = $query
            ->field($field)
            ->page($page, $limit)
            ->order('create_time desc,id desc')
            ->select()
            ->each(function ($item) {
                if (isset($item['operator']['user_name'])) {
                    $item['user_name'] = $item['operator']['user_name'];
                    unset($item['operator']);
                } elseif ($item['user_type'] == 2) {
                    $item['user_name'] = '客户自己';
                }
                return $item;
            })
            ->toArray();

        return ['code' => 0, 'message' => 'success', 'data' => ['list' => $list, 'total' => $total]];
    }

    /**
     * @describe
     * @author: Bobo
     * @date: 2025-03-05 14:10:59
     * @param $type 1: ERP后台预览合同，需要保存至文件柜 2: 商城预览合同，不需要保存至文件柜 @required
     * @return Renderable
     */
    public function contractPreview(int $orderId, int $type, string $creator = '')
    {

        $model = new OrderModel();
        $itmeModel = new OrderItem();
        $field = '
            a.id,
            a.user_id,
            a.order_no,
            a.delivery_method,
            a.order_category,
            a.first_name,
            a.last_name,
            a.country_name,
            a.state,
            a.city_name,
            a.address,
            a.phone,
            a.advance_amount,
            a.total_amount,
            a.id_number,
            a.signing_date,
            a.payment_deadline,
            a.shipping_end_date,
            a.shipping_start_date,
            a.contract_type,
            a.delivery_terms,
            a.transfer_payment_info,
            a.logistics_fee,
            a.notes,
            a.product_total_original_amount-a.product_total_amount as discount,
            a.first_leg_logistics_fee,
            b.abbr,
            c.cusname as customer_name';

        $order = $model->alias('a')
            ->join('transaction_currency b', 'b.id = a.currency')
            ->join('customer c', 'c.id = a.user_id')
            ->field($field)
            ->where([
                'a.is_del' => 0,
                'a.id' => $orderId
            ])
            ->find();


        if (!$order) {
            return ['code' => 1, 'message' => '订单不存在'];
        }
        $order = $order->toArray();

        if (isset($order['transfer_payment_info']) && $order['transfer_payment_info'] != '') {
            $transferPaymentList = $model->getFieldEnum('transfer_payment_info_detail');

            foreach ($transferPaymentList['transfer_payment_info_detail'] as $item) {
                if ($item['value'] == $order['transfer_payment_info']) {
                    $order['transfer_payment_info'] = $item['label']['detail_value'];
                    break; // 找到后跳出循环，提高效率
                }
            }
        }


        $order['shipping_address'] = $order['country_name'] . ' ' . $order['state'] . ' ' . $order['city_name'] . ' ' . $order['address'];
        $order['consignee'] = $order['first_name'] . ' ' . $order['last_name'];
        $order['delivery_terms'] = $order['delivery_terms'] == '1' ? 'Delivered Duty Paid' : 'Delivered Duty Unpaid';
        $order['discount'] = $order['discount'] < 0 ? 0.00 : $order['discount'];
        $order['product_list'] = $itmeModel->alias('a')
            ->leftJoin('product b', 'a.product_id = b.id')
            ->where([
                ['a.order_id', '=', $orderId],
                ['a.quantity', '>', 0]
            ])
            ->field('a.id,"服务器" as chain_name, b.cname as name,a.quantity,a.price_selected_currency as price,a.price_selected_currency * a.quantity as subtotle_price, "' . $order['abbr'] . '" as currency,b.expiration_date')
            ->select()
            ->toArray();
        $logic = new \app\admin\logic\Order\OrderContractPreview();

        $result = $logic->generateOrderInvoice($order, $type);

        if ($result['code'] == 1) {
            return ['code' => 1, 'message' => $result['message']];
        }

        if ($type != 1) {
            return ['code' => 0, 'message' => 'success', 'data' => ['url' => $result['filePath']]];
        }

        $upload = new \app\common\service\Upload();

        // 直接创建 UploadedFile 实例
        $fileObj = new UploadedFile($result['filePath'], basename($result['filePath']), mime_content_type($result['filePath']));

        // 传入 uploadFile() 方法
        $uploadRes = $upload->uploadFile($fileObj, 12);


        if (0 == $uploadRes['code']) {
            $filingcabinetModel = new Filingcabinet();

            // 查询是否已存在该订单的文件
            $isExist = $filingcabinetModel->where([
                'order_id' => $orderId,
            ])->find();
            // 开始事务
            $filingcabinetModel::startTrans();
            try {
                if ($isExist) {
                    // 删除旧文件（确保 file_id 存在）
                    if (!empty($isExist['file_id'])) {
                        $filingcabinetModel->name('images')->where('id', $isExist['file_id'])->delete();
                    }
                    // 更新已有记录
                    $isExist->save([
                        'file_id' => $uploadRes['data']['id'],
                        'title' => $uploadRes['data']['name'],
                        'update_time' => date('Y-m-d H:i:s')
                    ]);
                } else {
                    // 新增记录
                    $filingcabinetModel->save([
                        'file_type'   => 10,
                        'file_id'     => $uploadRes['data']['id'],
                        'title'       => $uploadRes['data']['name'],
                        'customer_id' => $order['user_id'],
                        'order_id'    => $orderId,
                        'order_type'  => $order['order_category'],
                        'creator'     => $creator,
                        'create_time' => date('Y-m-d H:i:s')
                    ]);
                }

                // 提交事务
                $filingcabinetModel::commit();

                $notificationService = new CompleteNotificationService();
                $customer = CustomerModel::where('id', $order['user_id'])->find();
                $notificationService->send('contract_created', $order, [$customer['owner']]);

                $this->logger->logOperation($orderId, 'order', '订单-上传文件柜', '订单-上传文件柜',1,'filingcabinet',$filingcabinetModel->id);

                return ['code' => 0, 'message' => 'success', 'data' => ['url' => $uploadRes['data']['url']]];
            } catch (\Throwable $th) {
                // 发生异常，回滚事务
                $filingcabinetModel::rollback();
                return ['code' => 1, 'message' => '文件保存失败：' . $th->getMessage()];
            }
        } else {
            return ['code' => 1, 'message' => '文件保存失败：' . $uploadRes['message']];
        }
    }









    /**
     * @describe 关联采购订单
     * @author: Bobo
     * @date: 2025-03-06 19:16:20
     * @param [type] @required
     * @return Renderable
     */
    public function getAsociatedPurchaseOrders(int $orderId, string $orderType)
    {
        // 统一模型实例，避免重复实例化
        $inventoryChangeRecordModel = new InventoryChangeRecord();
        $inventoryModel = new Inventory();
        $purchaseOrderModel = new PurchaseOrders();

        // 规范 orderType
        $orderType = ($orderType === 'order') ? 'order' : 'wholesal_order';

        // 查询 inventory_id 列表
        $list = $inventoryChangeRecordModel
            ->where([
                ['business_table_id', '=', $orderId],
                ['business_tabel_name', '=', $orderType]
            ])
            ->column('inventory_id'); // 直接获取 inventory_id 数组

        if (empty($list)) {
            return ['code' => 0, 'message' => 'success', 'data' => []];
        }

        // 去重
        $inventoryIds = array_unique($list);

        // 查询库存数据
        $inventoryList = $inventoryModel
            ->whereIn('id', $inventoryIds)
            ->column('source_table', 'source_id'); // 直接获取 source_id => source_table 映射数组

        $purchaseOrderIds = [];
        foreach ($inventoryList as $sourceId => $sourceTable) {
            $purchaseOrderIds[] = ($sourceTable === 'purchase_orders')
                ? $sourceId
                : $this->getPurchaseIdByInventoryId($sourceId);
        }

        // 去重
        $purchaseOrderIds = array_unique($purchaseOrderIds);

        if (empty($purchaseOrderIds)) {
            return ['code' => 0, 'message' => 'success', 'data' => []];
        }

        $payTypeList = $purchaseOrderModel->getFieldEnum('pay_type')['pay_type'];
        $payTermsList = $purchaseOrderModel->getFieldEnum('pay_terms')['pay_terms'];
        // 查询采购订单
        $purchaseOrderList = $purchaseOrderModel
            ->with(['getSignatoryidValue'])
            ->whereIn('id', $purchaseOrderIds)
            ->field('id,purchase_no,order_time,signatoryid,pay_time,pay_type,pay_terms,product_total_amount,other_amount,create_time')
            ->select()
            ->toArray();

        foreach ($purchaseOrderList as $key => $value) {
            $purchaseOrderList[$key]['pay_type'] = $payTypeList[$value['pay_type']] ?? '';
            $purchaseOrderList[$key]['pay_terms'] = $payTermsList[$value['pay_terms']] ?? '';
            $purchaseOrderList[$key]['total_amount'] = $value['product_total_amount'] + $value['other_amount'];
            $purchaseOrderList[$key]['product_total_amount'] = intval($value['product_total_amount']);
            $purchaseOrderList[$key]['other_amount'] = intval($value['other_amount']);
        }
        return ['code' => 0, 'message' => 'success', 'data' => $purchaseOrderList];
    }


    /**
     * @describe 获取库存的采购id
     * @author: Bobo
     * @date: 2025-03-07 11:14:53
     * @param [type] @required
     * @return Renderable
     */
    public function getPurchaseIdByInventoryId(int $inventoryId)
    {
        static $inventoryModel = null;

        if ($inventoryModel === null) {
            $inventoryModel = new Inventory();
        }

        while (true) {
            $inventory = $inventoryModel->where('id', $inventoryId)->find();
            if (empty($inventory)) {
                return 0;
            }
            if ($inventory['source_table'] === 'purchase_orders') {
                return $inventory['source_id'];
            }
            $inventoryId = $inventory['source_id'];
        }
    }
    public function remark($param)
    {
        $order = OrderModel::where([['id', '=', $param['id']]])->find();
        if (!$order) {
            return ['code' => 1, 'message' => '订单不存在'];
        }
        $order->order_remark = $param['order_remark'];
        $res = $order->save();
        if (!$res) {
            return ['code' => 1, 'message' => '修改失败'];
        }
        return ['code' => 0];
    }
    /**
     * 取消订单
     * @param $param
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 2025-03-11 14 40 39
     * author: jiang
     */
    public function cancel($param)
    {
        $order = OrderModel::where([['id', '=', $param['id']], ['status', '=', 10]])->find();
        if (!$order) {
            return ['code' => 1, 'message' => '订单不存在或状态不正确'];
        }

        Db::startTrans();
        try {
            // 判断订单类型
            if ($order->order_type == 2) { // 经销商发货单 只要取消就释放资产
                // 如果为经销商发货单 释放经销商资产
                $orderItems = $order->items->toArray();
                $wholesalAssets = new WholesalAssets();
                $result = $wholesalAssets->releaseAssets($orderItems);
                if ($result['code'] != 0) {
                    throw new \Exception($result['message']);
                }
            } else if ($order->pay_status == 4 && $order->order_type == 1 && $order->review_node != 1) { // review_node 为 1 时没有锁定库存，无需释放
                // 释放库存
                $items = $order->items->toArray();
                if (empty($items)) {
                    throw new \Exception('订单商品不存在');
                }
                $condition = [];
                $mergedItems = []; // 合并相同库存的商品

                foreach ($items as $item) {
                    if ($item['pending_quantity'] <= 0) {
                        continue;
                    }
                    $key = implode('_', [
                        $item['order_id'],
                        $item['product_id'],
                        $item['warehouse_id'],
                        $item['arrival_date'],
                        $item['is_futures']
                    ]);
                    if (!isset($mergedItems[$key])) {
                        // 如果不存在，创建新记录
                        $mergedItems[$key] = [
                            'order_id' => $item['order_id'],
                            'product_id' => $item['product_id'],
                            'wid' => $item['warehouse_id'],
                            'arrival_date' => $item['arrival_date'],
                            'is_futures' => $item['is_futures'],
                            'quantity' => $item['pending_quantity']
                        ];
                    } else {
                        // 如果存在，累加数量
                        $mergedItems[$key]['quantity'] += $item['pending_quantity'];
                    }
                }

                if (!empty($mergedItems)) {
                    // 将合并后的数据转换为数组
                    $condition = array_values($mergedItems);
                    // 释放锁定库存
                    $inventory = new CommonInventoryService();
                    $lockResult = $inventory->unlockInventory($condition);
                    if (!$lockResult) {
                        throw new \Exception('库存释放失败，请确认库存情况');
                    }
                }
            }

            // 更新订单状态
            $order->status = 70;
            $order->updater = $param['operator_id'];
            $order->update_time = date('Y-m-d H:i:s');
            if (!$order->save()) {
                throw new \Exception('订单状态更新失败');
            }

            if ($order->pay_status == 4 && $order->order_type !== 2 && !in_array($order->source, [2, 3])) {
                // 创建退货退款单

                $payments = OrderPaymentModel::where([
                    'order_id' => $order->id,
                    'status' => '01',
                    'pay_type' => '00'
                ])->field('id,paid_amount as amount,transfer_type,notes')
                    ->select()
                    ->toArray();

                if (count($payments) == 0) {
                    throw new \Exception('订单支付信息不存在');
                }

                $oCustomerModel = CustomerModel::where('id', $order->user_id)->find();
                if (!$oCustomerModel) {
                    throw new \Exception('客户不存在');
                }


                $is_have_returnorder = Db::name('returnorder')->where('order_id', $order->id)->where('status', '<>', 4)->find();
                if (!$is_have_returnorder) {
                    $args = [];
                    $args['creator'] = $param['operator_id'];
                    $args['returnorder_type'] = 1;
                    $args['customer_id'] = $order->user_id;
                    $args['order_id'] = $order->id;
                    $args['products_list'] = [];
                    $args['signatory'] = $param['operator_id'];
                    $args['signing_date'] = date('Y-m-d');
                    $args['owner'] = $oCustomerModel->owner;
                    $args['partner'] = $oCustomerModel->partner ? explode(',', $oCustomerModel->partner) : [];
                    $args['total_amount'] = $order->pay_amount;
                    $args['remark'] = null;
                    $args['operator_id'] = $param['operator_id'];
                    $args['payment_list'] = $payments;

                    $service = new Returnorder();
                    $result = $service->save($args);
                    if ($result['code'] !== 0) {
                        throw new \Exception($result['message']);
                    }
                }
            }
            $this->logger->logOperation($param['id'], 'order', '订单-取消', '取消订单');
            Db::commit();

            $notificationService = new CompleteNotificationService();
            try {
                $partnerArr = $order->partner ? array_filter(explode(',', $order->partner)) : [];
                $recipients = array_merge([$order->owner, $order->signatory, ...$partnerArr]);
                $notificationService->send('order_cancel', $order->toArray(), $recipients);
            } catch (\Exception $notifyException) {
                Log::error('订单取消通知失败: ' . $notifyException->getMessage() . ' 订单编号: ' . $order->order_no . ' 文件：' . $notifyException->getFile() . ' | 行号：' . $notifyException->getLine());
            }
        } catch (\Exception $e) {
            Db::rollback();
            return ['code' => 1, 'message' => $e->getMessage()];
        }
        if ($order->status == 70) {
            /* 修改GoAffPro订单状态 */
            $GoAffPro = new GoAffPro();
            $GoAffPro->updateAffiliateOrder(false, $order->id);
        }
        #hsopify订单取消，通知shopify
        if ($order->source == 2) {
            $shopifyId = Db::name('order_shopify_relation')->where('order_id', $order->id)->value('shopify_order_id');
            Log::info(' shopify id :' . $shopifyId);
            $shopify = new OrderService();
            $cancle = $shopify->cancelShopifyOrderApi($shopifyId);
            Log::info(' shopify api return  :' . $cancle);
            if (!$cancle) {
                return ['code' => 1, 'message' => 'shopify订单取消失败'];
            }
        }
        return ['code' => 0, 'message' => 'success'];
    }

    /**
     * @describe 锁定库存 用于锁定支付成功之后锁定库存的订单
     * @author: Bobo
     * @date: 2025-06-05 15:37:48
     * @param [type] @required
     * @return Renderable
     */
    public function lockInventory($param)
    {
        $order = OrderModel::where([
            'id' => $param['id'],
            'is_del' => 0,
            'review_node' => 1
        ])->whereIn('status', [10, 30, 100])->find();

        if (!$order) {
            return ['code' => 1, 'message' => '订单不存在或状态不正确'];
        } else {
            $inventoryService = new InventoryService();
            $result = $inventoryService->lockInventory(['id' => $order->id, 'operator_id' => $param['operator_id']]);
            if ($result) {
                $origin_exceptionstatus = $order->exceptionstatus;
                if ($origin_exceptionstatus && strpos($origin_exceptionstatus, ',') !== false) {
                    $origin_exceptionstatus = explode(',', $origin_exceptionstatus);
                    $new_exceptionstatus = array_filter($origin_exceptionstatus, function ($item) {
                        return $item != 1;
                    });
                    $new_exceptionstatus = implode(',', $new_exceptionstatus);
                } else {
                    $new_exceptionstatus = null;
                }
                $order->exceptionstatus = $new_exceptionstatus;
                $order->review_node = 0;
                $order->save();
                $this->logger->logOperation($order->id, 'order', '订单-锁定库存', '订单锁定库存成功');
                return ['code' => 0, 'message' => 'success'];
            } else {
                $this->logger->logOperation($order->id, 'order', '订单-锁定库存', '订单锁定库存失败');
                return ['code' => 1, 'message' => '库存锁定失败，请确认库存情况'];
            }
        }
    }


    /**
     * @describe
     * @author: Bobo
     * @date: 2025-08-11 18:31:29
     * @param [type] @required
     * @return Renderable
     */
    public function checkExceptionOrderItem($param)
    {

        $order = OrderModel::where([
            'id' => $param['id'],
            'is_del' => 0,
        ])->find();
        if (!$order) {
            return ['code' => 1, 'message' => '订单不存在或状态不正确'];
        }
        $orderItemIds = array_column($param['product_list'], 'id');
        $orderItem = OrderItemModel::where('order_id', $param['id'])->whereIn('id', $orderItemIds)->select();
        if (count($orderItem) == 0 || count($orderItem) != count($orderItemIds)) {
            return ['code' => 1, 'message' => '订单商品不存在'];
        }

        $productList = array_column($param['product_list'], null, 'id');
        $message = 'success';
        Db::startTrans();
        try {
            foreach ($orderItem as $item) {
                foreach ($productList as $product) {
                    if ($product['id'] == $item->id) {
                        $item->product_id = $product['product_id'];
                        $item->warehouse_id = $product['wid'];
                        $item->is_futures = $product['is_futures'];
                        $item->arrival_date = $product['arrival_date'];
                        $item->real_arrival_date = $product['real_arrival_date'];
                        $item->exceptionstatus = null;
                        $item->save();
                    }
                }
            } // 更新订单商品明细


            $order->exceptionstatus = null;
            $order->updater = $param['operator_id'];
            $order->update_time = date('Y-m-d H:i:s');
            $order->save();
            Db::commit();
        } catch (\Throwable $th) {
            Db::rollback();
            return ['code' => 1, 'message' => $th->getMessage()];
        }

        if ($order->review_node == 1 && $message == 'success') {
            $inventoryService = new InventoryService();
            $result = $inventoryService->lockInventory(['id' => $order->id, 'operator_id' => $param['operator_id']], 0);
            if (!$result) {
                $message = '库存锁定失败，请确认库存情况';
            } else {
                $order->review_node = 0;
                $order->updater = $param['operator_id'];
                $order->update_time = date('Y-m-d H:i:s');
                $order->save();
            }
        }

        $this->logger->logOperation($param['id'], 'order', '订单-校对商品', '订单校对商品');
        return ['code' => 0, 'message' => $message];
    }

    /**
     * @describe 订单无需发货
     * @author: Bobo
     * @date: 2025-08-14 19:19:46
     * @param [type] @required
     * @return Renderable
     */
    public function noDelivery($param)
    {
        $order = OrderModel::where([
            'id' => $param['id'],
            'is_del' => 0,
        ])->find();
        if (!$order) {
            return ['code' => 1, 'message' => '订单不存在或状态不正确'];
        }
        $orderItem = OrderItemModel::where([
            'id' => $param['order_item_id'],
            'order_id' => $param['id'],
        ])->find();
        if (!$orderItem) {
            return ['code' => 1, 'message' => '订单商品不存在'];
        }

        if ($orderItem->pending_quantity == 0) {
            return ['code' => 1, 'message' => '订单待发货商品数量为0'];
        }



        $orderTotalPendingQuantity = OrderItemModel::where([
            'order_id' => $param['id'],
            'id' => ['neq', $param['order_item_id']],
            'quantity' => ['gt', 0], // 商品初始数量大于0,
            'is_del' => 0
        ])->sum('pending_quantity');

        $operator_name = Db::name('operator')->where('id', $param['operator_id'])->value('cname');

        Db::startTrans();
        try {
            $originalPendingQuantity = $orderItem->pending_quantity;
            $orderItem->pending_quantity = 0;
            $orderItem->remark = $operator_name ? $operator_name . '于' . date('Y-m-d H:i:s') . '操作了无需发货' : '于' . date('Y-m-d H:i:s') . '操作了无需发货';
            $orderItem->save();


            if ($orderTotalPendingQuantity == 0 && $order->status == 30) { // 订单待收货状态 商品待发数量为0 则将订单状态改为已完成
                $order->status = 100;
            }
            $order->updater = $param['operator_id'];
            $order->update_time = date('Y-m-d H:i:s');
            $order->last_delivery_time = date('Y-m-d');
            $order->save();


            $condition = [
                [
                    'order_id' => $param['id'],
                    'product_id' => $orderItem->product_id,
                    'wid' => $orderItem->warehouse_id,
                    'arrival_date' => $orderItem->arrival_date,
                    'is_futures' => $orderItem->is_futures,
                    'quantity' => $originalPendingQuantity
                ]
            ];
            // 释放锁定库存
            $inventory = new CommonInventoryService();
            $lockResult = $inventory->unlockInventory($condition);
            if (!$lockResult) {
                throw new \Exception('库存释放失败，请确认库存情况');
            }

            Db::commit();
            return ['code' => 0, 'message' => 'success'];
        } catch (\Throwable $th) {
            Db::rollback();
            return ['code' => 1, 'message' => $th->getMessage()];
        }
    }

    /**
     * @describe
     * @author: Bobo
     * @date: 2025-08-20 15:26:29
     * @param [type] @required
     * @return Renderable
     */
    public function getReviewInfo(int $id)
    {
        $order = OrderModel::where([
            'id' => $id,
            'is_del' => 0,
        ])->field('id,user_id,order_no,total_amount,pay_amount,product_total_amount,product_total_original_amount,logistics_fee,first_leg_logistics_fee,status,pay_status,delivery_method,review_node,order_category,creator,create_time,updater,update_time,
        delivery_method,first_name,last_name,phone,email,zip_code,address,address2,company,prescription,country_id,city_id,country_name,city_name,state_id,state,delivery_remark')
            ->with(['itemList', 'creator', 'updater', 'customer', 'logger'])
            ->find();


        $redis = (new RedisClient())->getClient();
        $originalOrder = $redis->get('update_original_data_id:' . $id);
        if (!$originalOrder) {
            return ['code' => 1, 'message' => '订单不存在或状态不正确'];
        }
        $originalOrder = json_decode($originalOrder, true);

        $all_original_order_items_warehouse_ids = array_column($originalOrder['items'], 'warehouse_id');

        $all_warehouse_ids = array_unique(array_map('intval', $all_original_order_items_warehouse_ids));

        $all_warehouse = WarehouseModel::whereIn('id', $all_warehouse_ids)->select()->toArray();
        $all_warehouse = array_column($all_warehouse, null, 'id');



        if ($originalOrder && isset($originalOrder['items']) && $originalOrder['items']) {
            foreach ($originalOrder['items'] as &$item) {
                $item['warehouse_name'] = $all_warehouse[$item['warehouse_id']]['name'];
                $item['actual_quoted_currency_name'] = Db::table('db_transaction_currency')->where('id', $item['transaction_currency_id'])->field('name')->find()['name'];
                unset($item['warehouses']);
            }
            $order->originalItemList = $originalOrder['items'];
        }

        foreach ($order->itemList as $key => $value) {
            $order->itemList[$key]['actual_quoted_currency_name'] = Db::table('db_transaction_currency')->where('id', $value['transaction_currency_id'])->field('name')->find()['name'];
            unset($order->itemList[$key]['warehouses']);
        }

        $order = $order->toArray();
        $order['originalStatus'] = $originalOrder['status'];

        $order['payment'] = $this->getOrderPayment($order, ['01']);

        $order['delivery'] = $this->getOrderDelivery($order);

        $order['logistics'] = $this->getOrderLogistics($order);

        if (!$order) {
            return ['code' => 1, 'message' => '订单不存在或状态不正确'];
        }
        return ['code' => 0, 'data' => $order];
    }
    /**
     * @describe
     * @author: Bobo
     * @date: 2025-08-25 15:40:33
     * @param [type] @required
     * @return Renderable
     */
    private function getOrderPayment($order, $status)
    {
        $orderPayment = OrderPaymentModel::where('order_id', $order['id'])
            ->with(['pay_currency', 'creator', 'reviewer'])
            ->whereIn('status', $status)
            ->append(['status_text'])
            ->select()

            ->toArray();
        if (count($orderPayment) == 0) {
            return [];
        }
        $all_voucher_id = array_column($orderPayment, 'transfer_voucher_id');
        $all_voucher_id = array_unique(array_map('intval', explode(',', implode(',', $all_voucher_id))));

        if (count($all_voucher_id) > 0) {
            $oImages = new Images();
            $imgObject = $oImages->getImagesByIds($all_voucher_id);
            $imgObject = array_column($imgObject, null, 'id');

            foreach ($orderPayment as $key => $value) {
                $transfer_voucher_id = explode(',', $value['transfer_voucher_id']);

                foreach ($transfer_voucher_id as $voucher_id) {
                    $orderPayment[$key]['transfer_voucher_url'][] = $imgObject[$voucher_id];
                }
                $orderPayment[$key]['transfer_voucher_url'] = array_values($orderPayment[$key]['transfer_voucher_url']);
            }
        }
        return $orderPayment;
    }


    /**
     * @describe 获取订单发货信息
     * @author: Bobo
     * @date: 2025-08-25 15:40:33
     * @param [type] @required
     * @return Renderable
     */
    private function getOrderDelivery(&$order)
    {
        $delivery =  [
            'name' => $order['first_name'] . ' ' . $order['last_name'],
            'phone' => $order['phone'],
            'email' => $order['email'],
            'zip_code' => $order['zip_code'],
            'address' => $order['address'],
            'address2' => $order['address2'],
            'company' => $order['company'],
            'prescription' => $order['prescription'],
            'country_id' => $order['country_id'],
            'city_id' => $order['city_id'],
            'country_name' => $order['country_name'],
            'city_name' => $order['city_name'],
            'state_id' => $order['state_id'],
            'state' => $order['state'],
            'first_name' => $order['first_name'],
            'last_name' => $order['last_name'],
            'delivery_remark' => $order['delivery_remark']
        ];
        unset($order['first_name'], $order['last_name'], $order['phone'], $order['email'], $order['zip_code'], $order['address'], $order['address2'], $order['company'], $order['prescription'], $order['country_id'], $order['city_id'], $order['country_name'], $order['city_name'], $order['state_id'], $order['state'], $order['delivery_remark']);
        return $delivery;
    }


    /**
     * @describe 获取订单物流信息
     * @author: Bobo
     * @date: 2025-08-25 15:40:33
     * @param [type] @required
     * @return Renderable
     */
    private function getOrderLogistics(&$order)
    {
        // 查询所有物流订单项，并联接相关数据
        $logisticsItems = Db::name('logistics_order_item')
            ->alias('a')
            ->leftJoin('db_logistics_order b', 'a.logistics_order_id = b.id')
            ->where('a.order_id', $order['id'])
            ->where('b.type', 1)
            ->field('a.order_id,
             a.logistics_order_id,
             a.product_id,
             a.warehouse_id,
             a.number,
             a.create_time,
             b.company_id,
             b.logistics_no,
             b.logistics_voucher,
             b.cost,
             b.transaction_currency_id,
             b.notes,
             b.status,
             b.serial_number,
             b.ship_date')
            ->select()
            ->toArray();

        // 提前查询所有产品和仓库信息，存入数组
        $productIds = array_column($logisticsItems, 'product_id');
        $warehouseIds = array_column($logisticsItems, 'warehouse_id');

        $products = Db::name('product')
            ->whereIn('id', $productIds)
            ->field('id, code as product_code, cname as product_name')
            ->select()->toArray();
        $products = array_column($products, null, 'id');

        $warehouses = Db::name('warehouse')
            ->whereIn('id', $warehouseIds)
            ->field('id, name as warehouse_name')
            ->select()->toArray();
        $warehouses = array_column($warehouses, null, 'id');

        // 提前处理图片数据，避免每次循环都查询
        $oImages = new Images();

        // 用于存储合并后的物流数据
        $mergedLogistics = [];
        // 遍历物流订单项，合并数据
        foreach ($logisticsItems as $item) {
            $logisticsId = $item['logistics_order_id'];
            $product = $products[$item['product_id']] ?? [];
            $warehouse = $warehouses[$item['warehouse_id']] ?? [];
            // 物流项明细
            $logisticsItem = [
                'product_id' => $item['product_id'],
                'product_name' => $product['product_name'] ?? '',
                'product_code' => $product['product_code'] ?? '',
                'warehouse_name' => $warehouse['warehouse_name'] ?? '',
                'number' => $item['number'],
            ];
            if (isset($mergedLogistics[$logisticsId])) {
                $mergedLogistics[$logisticsId]['children'][] = $logisticsItem;
                continue;
            }
            // 处理物流凭证
            $voucherUrls = [];
            if (!empty($item['logistics_voucher'])) {
                $voucherIds = array_filter(array_unique(explode(',', $item['logistics_voucher'])));
                $voucherUrls = $oImages->getImagesByIds($voucherIds);
            }
            if (!empty($item['cost'])) {
                $item['cost'] = json_decode($item['cost']);
            }
            // 如果物流订单不存在，初始化数据
            $mergedLogistics[$logisticsId] = [
                'id' => $logisticsId,
                'company' => $item['company_id'],
                'logistics_no' => $item['logistics_no'],
                'cost' => $item['cost'],
                'transaction_currency_id' => $item['transaction_currency_id'],
                'notes' => $item['notes'],
                'create_time' => $item['create_time'],
                'logistics_voucher' => $voucherUrls,
                'status_value' => (new LogisticsOrderModel())->getAttributes('status')[$item['status']] ?? '',
                'status' => $item['status'],
                'ship_date' => $item['ship_date'],
                'serial_number' => $item['serial_number']
            ];
            $mergedLogistics[$logisticsId]['children'][] = $logisticsItem;
        }

        return array_values($mergedLogistics);
    }
    /**
     * 订单审核
     * @param $param
     * @return array|void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     * 2024-11-20 17 07 35
     * author: jiang
     */
    public function examine($param)
    {
        $where = [
            ['id', '=', $param['id']],
            ['status', '=', 20],
            ['is_del', '=', 0],
            // ['pay_status', '=', 1]
        ];

        $oOrderModel = OrderModel::where($where)->find();
        if (!$oOrderModel) {
            return ['code' => 1, 'message' => '数据不存在！'];
        }
        switch ($oOrderModel->review_node) {
            case 4:
                $oOrderModel->status = 21;
                $oOrderModel->review_node = 0;
                if (!$oOrderModel->save()) {
                    return ['code' => 1, 'message' => '审核失败！'];
                }

                $this->logger->logOperation($oOrderModel->id, 'order', '创建订单审核通过', '创建订单审核通过');
                break;
            case 2:
                if ($param['is_approved'] == false) { // 审核不通过
                    $result = $this->rejectUpdateOrder($oOrderModel->id);
                    if ($result['code'] == 1) {
                        return ['code' => 1, 'message' => $result['message']];
                    }
                } else {
                    $result = $this->approveUpdateOrder($oOrderModel->id, $param);
                    if ($result['code'] == 1) {
                        return ['code' => 1, 'message' => $result['message']];
                    }
                }
                $redis = (new RedisClient())->getClient();
                $redis->del('update_original_data_id:' . $oOrderModel->id);
                $notificationService = new CompleteNotificationService();

                $recipients = [$oOrderModel->owner, $oOrderModel->signatory];

                if ($oOrderModel->partner) {
                    $recipients = array_unique(array_merge($recipients, explode(',', $oOrderModel->partner)));
                }
                $orderInfo = $oOrderModel->toArray();
                $operator = \app\admin\model\Operator::where('id', $param['operator_id'])->value('cname');
                $content = $param['is_approved'] ? "已审核通过您的订单" : "已审核驳回您的订单";
                $orderInfo['title']  = $operator.$content;
                $notificationService->send('order_complete_review',$orderInfo , $recipients);
                $approverWhere = [
                    'entity_id' => $oOrderModel->id,
                    'business_module' => 'order',
                    'operate' => '订单-编辑',

                ];
                $this->logger->updateApprover($approverWhere,$param['operator_id']);
                $this->logger->logOperation($oOrderModel->id, 'order',$param['is_approved'] ? '订单-审核通过':'订单-审核驳回', $param['is_approved'] ? '更新订单审核通过' : '更新订单审核驳回');
                break;
            case 5:
                if (2 == $oOrderModel->order_type && 0 == $oOrderModel->logistics_fee) { // 经销商发货订单 运费为0 审核通过，状态直接改为待发货
                    $oOrderModel->status = 30;
                } else {
                    $oOrderModel->status = 21;
                }
                $oOrderModel->review_node = 0;
                if (!$oOrderModel->save()) {
                    return ['code' => 1, 'message' => '审核失败！'];
                }
                if (30 == $oOrderModel->status) { // 待发货状态 发送通知
                    $notificationService = new CompleteNotificationService();
                    $notificationService->send('order_delivery_pending', $oOrderModel->toArray(), [], '', '50,51');
                }
                $this->logger->logOperation($oOrderModel->id, 'order', '运费为空审核通过', '运费为空审核通过');
                break;
            default:

                return ['code' => 1, 'message' => '审核失败！'];
        }
        return ['code' => 0, 'message' => '操作成功！'];
    }

    /**
     * @describe 订单修改审核不通过
     * @author: Bobo
     * @date: 2025-08-21 18:43:23
     * @param [type] @required
     * @return Renderable
     */
    private function rejectUpdateOrder($orderId)
    {
        $redis = (new RedisClient())->getClient();
        $originalOrder = $redis->get('update_original_data_id:' . $orderId);
        if (!$originalOrder) {
            return ['code' => 1, 'message' => '订单不存在或状态不正确'];
        }
        $originalOrder = json_decode($originalOrder, true);

        $order_items = $originalOrder['items'];
        unset($originalOrder['items']);
        unset($originalOrder['id']);

        $current_order_items_ids = OrderItemModel::where('order_id', $orderId)->column('id');
        $original_order_items_ids = array_column($order_items, 'id');
        $delete_order_items_ids = array_diff($current_order_items_ids, $original_order_items_ids);
        Db::startTrans();
        try {
            OrderModel::where('id', $orderId)->update($originalOrder);
            Log::info('驳回订单更新update_original_data_id: ' . json_encode($originalOrder));
            foreach ($order_items as $item) {
                unset($item['warehouses'], $item['product_name'], $item['style_code'], $item['unit'], $item['unit_sum'], $item['code'], $item['brand'], $item['hashrate'], $item['expiration_date'], $item['computing_unit'], $item['billing_weight']);
                OrderItemModel::where('id', $item['id'])->update($item);
                $last_sql = Db::getLastSql();
                Log::info('驳回订单更新update_original_data_id: ' . $last_sql);
            }
            $delete_order_items = OrderItemModel::where('id', 'in', $delete_order_items_ids)->update(['is_del' => time()]);
            Db::commit();
        } catch (\Throwable $th) {
            Db::rollback();
            return ['code' => 1, 'message' => $th->getMessage()];
        }
        return ['code' => 0, 'message' => '操作成功'];
    }
    /**
     * @describe 订单修改审核通过
     * @author: Bobo
     * @date: 2025-08-21 18:43:23
     * @param [type] @required
     * @return Renderable
     */
    private function approveUpdateOrder($orderId, $param)
    {
        $order_data = $this->getReviewInfo($orderId);

        $order_data = $order_data['data'];



        // 1. 释放原锁定库存
        $productList = $order_data['originalItemList'];

        $condition = [];
        foreach ($productList as $item) {
            if ($item['pending_quantity'] == 0) {
                continue;
            }
            $key = $item['product_id'] . '_' . $item['warehouse_id'] . '_' . $item['arrival_date'] . '_' . $item['is_futures'];

            if (isset($condition[$key])) {
                $condition[$key]['quantity'] += $item['pending_quantity'];
            } else {
                $condition[$key] = [
                    'order_id' => $orderId,
                    'operator_id' => $param['operator_id'] ?? null,
                    'product_id' => $item['product_id'],
                    'wid' => $item['warehouse_id'],
                    'warehouse_id' => $item['warehouse_id'],
                    'arrival_date' => $item['arrival_date'],
                    'is_futures' => $item['is_futures'],
                    'quantity' => $item['pending_quantity']
                ];
            }
        }

        $order_items_total = array_sum(array_column($order_data['itemList'], 'quantity')); // 订单商品总数
        $order_items_total_shipped = array_sum(array_column($order_data['itemList'], 'pending_quantity')); // 订单商品已发货数量
        $inventory = new CommonInventoryService();
        Db::startTrans();
        try {
            // 释放原始锁定库存
            $lockResult = $inventory->unlockInventory($condition);
            if (!$lockResult) {
                throw new \Exception('库存释放失败，请确认库存情况');
            }
            if ($order_data['total_amount'] > $order_data['pay_amount']) { // 总金额大于支付金额，订单状态改为待支付
                $order_status = 10;
                $pay_status = 4; // 部分支付
            } else { // 总金额小于等于支付金额，订单状态改为待发货
                $pay_status = 3; // 已支付
                if ($order_items_total_shipped == $order_items_total) { // 订单商品已发货数量等于订单商品总数，订单状态改为待发货
                    $order_status = 30;
                } else {
                    $order_status = 40;
                }

                if ('wholesal' == $order_data['order_category']) {
                    $order_status = 100; // 经销商资产订单状态 已完成
                }
            }
            Db::name('order')->where('id', $orderId)->update(['status' => $order_status, 'review_node' => 0, 'pay_status' => $pay_status]);
            Log::info('编辑订单,审核成功: id' . $orderId . '库存释放成功，释放详情' . json_encode($condition));
            Db::commit();
        } catch (\Throwable $th) {
            Db::rollback();
            Log::error('编辑订单,审核失败: id' . $orderId . '库存释放失败，释放详情' . json_encode($condition) . 'message: ' . $th->getMessage() . '---line: ' . $th->getLine() . '---file: ' . $th->getFile());
            return ['code' => 1, 'message' => $th->getMessage()];
        }

        $newOrderItemList = Db::name('order_item')->where('order_id', $orderId)->where('is_del', 0)->where('quantity', '>', 0)->select()->toArray();
        $new_condition = [];
        foreach ($newOrderItemList as $newitem) {
            if ($newitem['pending_quantity'] == 0) {
                continue;
            }
            $key = $newitem['product_id'] . '_' . $newitem['warehouse_id'] . '_' . $newitem['arrival_date'] . '_' . $newitem['is_futures'];
            if (isset($new_condition[$key])) {
                $new_condition[$key]['quantity'] += $newitem['pending_quantity'];
            } else {
                if (empty($newitem['arrival_date'])) {
                    $newitem['arrival_date'] = null;
                }
                $new_condition[$key] = [
                    'order_id' => $orderId,
                    'operator_id' => $param['operator_id'] ?? null,
                    'product_id' => $newitem['product_id'],
                    'wid' => $newitem['warehouse_id'],
                    'warehouse_id' => $newitem['warehouse_id'],
                    'arrival_date' => $newitem['arrival_date'],
                    'is_futures' => $newitem['is_futures'],
                    'quantity' => $newitem['pending_quantity']
                ];
            }
        }

        // 锁定新修改的库存
        $lockResult = $inventory->lockInventoryByItem($new_condition);
        if (!$lockResult) {
            Db::startTrans();
            try {

                // 循环修改每个订单项的异常状态
                foreach ($new_condition as $condition) {
                    $where = [
                        'order_id' => $orderId,
                        'product_id' => $condition['product_id'],
                        'warehouse_id' => $condition['warehouse_id'],
                        'is_futures' => $condition['is_futures']
                    ];

                    // 处理arrival_date
                    if (empty($condition['arrival_date'])) {
                        $where[] = ['arrival_date', 'exp', Db::raw('IS NULL')];
                    } else {
                        $where['arrival_date'] = $condition['arrival_date'];
                    }


                    Db::name('order_item')->where($where)->update(['exceptionstatus' => 1]);
                }

                Db::name('order')->where('id', $orderId)->update([
                    'exceptionstatus' => 1,
                    'review_node' => 1,
                    'updater' => $param['operator_id'],
                    'update_time' => date('Y-m-d H:i:s')
                ]);

                Log::error('编辑订单,审核成功，库存锁定失败，修改订单异常状态成功: ' . json_encode($new_condition));
                Db::commit();
            } catch (\Throwable $th) {
                Db::rollback();

                Log::error('编辑订单,审核成功，库存锁定失败，修改订单异常状态失败: ' . json_encode($new_condition) . 'message: ' . $th->getMessage() . '---line: ' . $th->getLine() . '---file: ' . $th->getFile());

                return ['code' => 0,  'message' => '审核成功，库存锁定失败，请确认库存情况'];
            }

            return ['code' => 0, 'message' => '审核成功，库存锁定失败，请确认库存情况'];
        }
        Log::info('编辑订单,审核成功，库存锁定成功: ' . json_encode($new_condition));

        return ['code' => 0, 'message' => '审核成功'];
    }

    /**
     * @describe 获取库存转换信息
     * @author: Bobo
     * @date: 2025-08-26 18:05:04
     * @param $orderId 订单ID
     * @param $orderItemId 订单明细ID
     * @param $wholesalId 经销商订单ID
     * @return array
     */
    public function getInventoryTransSaveInfo($orderId, $orderItemId, $wholesalId)
    {
        $orderTransSaveLogic = new OrderTransSaveLogic();
        return $orderTransSaveLogic->getInventoryTransSaveInfo($orderId, $orderItemId, $wholesalId);
    }

    /**
     * @describe 导出订单数据
     * @author: Bobo
     * @date: 2025-09-03 13:33:01
     * @param [type] @required
     * @return Renderable
     */
    public function export()
    {
        $imporAndExportLogic = new ImporAndExportLogic();
        return $imporAndExportLogic->export();
    }
}
